1
0
mirror of https://github.com/MariaDB/server.git synced 2025-08-07 00:04:31 +03:00

Merge 10.6 into 10.7

This commit is contained in:
Marko Mäkelä
2022-08-30 13:02:42 +03:00
52 changed files with 1053 additions and 332 deletions

View File

@@ -343,7 +343,7 @@ check_server_version(unsigned long version_number,
}
/*********************************************************************//**
Receive options important for XtraBackup from MySQL server.
Receive options important for XtraBackup from server.
@return true on success. */
bool get_mysql_vars(MYSQL *connection)
{
@@ -1843,8 +1843,8 @@ static std::string make_local_paths(const char *data_file_path)
bool write_backup_config_file()
{
int rc= backup_file_printf("backup-my.cnf",
"# This MySQL options file was generated by innobackupex.\n\n"
"# The MySQL server\n"
"# This options file was generated by innobackupex.\n\n"
"# The server\n"
"[mysqld]\n"
"innodb_checksum_algorithm=%s\n"
"innodb_data_file_path=%s\n"
@@ -1929,7 +1929,7 @@ flush_changed_page_bitmaps()
/*********************************************************************//**
Deallocate memory, disconnect from MySQL server, etc.
Deallocate memory, disconnect from server, etc.
@return true on success. */
void
backup_cleanup()

View File

@@ -6265,22 +6265,28 @@ static bool check_all_privileges()
}
/* KILL ... */
if ((!opt_no_lock && (opt_kill_long_queries_timeout || opt_lock_ddl_per_table))
/* START SLAVE SQL_THREAD */
/* STOP SLAVE SQL_THREAD */
|| opt_safe_slave_backup) {
if (!opt_no_lock && (opt_kill_long_queries_timeout || opt_kill_long_query_type)) {
check_result |= check_privilege(
granted_privileges,
"SUPER", "*", "*",
"CONNECTION ADMIN", "*", "*",
PRIVILEGE_WARNING);
}
/* START SLAVE SQL_THREAD */
/* STOP SLAVE SQL_THREAD */
if (opt_safe_slave_backup) {
check_result |= check_privilege(
granted_privileges,
"REPLICATION SLAVE ADMIN", "*", "*",
PRIVILEGE_WARNING);
}
/* SHOW MASTER STATUS */
/* SHOW SLAVE STATUS */
if (opt_galera_info || opt_slave_info
|| (opt_no_lock && opt_safe_slave_backup)) {
|| opt_safe_slave_backup) {
check_result |= check_privilege(granted_privileges,
"REPLICATION CLIENT", "*", "*",
"SLAVE MONITOR", "*", "*",
PRIVILEGE_WARNING);
}

View File

@@ -174,7 +174,7 @@ INSERT INTO global_suppressions VALUES
/* Added 2009-08-XX after fixing Bug #42408 */
("Although a path was specified for the .* option, log tables are used"),
("Although a .* file was specified, log tables are used. To enable logging to files "),
("Backup: Operation aborted"),
("Restore: Operation aborted"),
("Restore: The grant .* was skipped because the user does not exist"),

View File

@@ -3042,6 +3042,122 @@ a
3
2
drop table t1,t2,t3;
#
# MDEV-29139: Redundant IN/ALL/ANY predicand in GROUP BY clause of
# IN/ALL/ANY/EXISTS subquery
#
create table t1 (a int);
create table t2 (b int);
create table t3 (c int);
create table t4 (d int);
insert into t1 values (3), (1);
insert into t2 values (3), (2);
insert into t3 values (4), (2);
insert into t4 values (1), (7);
explain extended select b from t2
where exists (select c from t3
group by (select a from t1 where a = 1) in (select d from t4));
id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t2 ALL NULL NULL NULL NULL 2 100.00
2 SUBQUERY t3 ALL NULL NULL NULL NULL 2 100.00
Warnings:
Note 1003 /* select#1 */ select `test`.`t2`.`b` AS `b` from `test`.`t2` where 1
select b from t2
where exists (select c from t3
group by (select a from t1 where a = 1) in (select d from t4));
b
3
2
prepare stmt from "select b from t2
where exists (select c from t3
group by (select a from t1 where a = 1) in (select d from t4))";
execute stmt;
b
3
2
execute stmt;
b
3
2
deallocate prepare stmt;
explain extended select b from t2
where exists (select c from t3
group by (select a from t1 where a = 1) >=
any (select d from t4));
id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t2 ALL NULL NULL NULL NULL 2 100.00
2 SUBQUERY t3 ALL NULL NULL NULL NULL 2 100.00
Warnings:
Note 1003 /* select#1 */ select `test`.`t2`.`b` AS `b` from `test`.`t2` where 1
select b from t2
where exists (select c from t3
group by (select a from t1 where a = 1) >=
any (select d from t4));
b
3
2
explain extended select b from t2
where exists (select c from t3
group by (select a from t1 where a = 1) <
all (select d from t4));
id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t2 ALL NULL NULL NULL NULL 2 100.00
2 SUBQUERY t3 ALL NULL NULL NULL NULL 2 100.00
Warnings:
Note 1003 /* select#1 */ select `test`.`t2`.`b` AS `b` from `test`.`t2` where 1
select b from t2
where exists (select c from t3
group by (select a from t1 where a = 1) <
all (select d from t4));
b
3
2
explain extended select b from t2
where b in (select c from t3
group by (select a from t1 where a = 1) in (select d from t4));
id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t2 ALL NULL NULL NULL NULL 2 100.00
1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 func 1 100.00
2 MATERIALIZED t3 ALL NULL NULL NULL NULL 2 100.00
Warnings:
Note 1003 select `test`.`t2`.`b` AS `b` from `test`.`t2` semi join (`test`.`t3`) where 1
select b from t2
where b in (select c from t3
group by (select a from t1 where a = 1) in (select d from t4));
b
2
explain extended select b from t2
where b >= any (select c from t3
group by (select a from t1 where a = 1) in
(select d from t4));
id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t2 ALL NULL NULL NULL NULL 2 100.00 Using where
2 SUBQUERY t3 ALL NULL NULL NULL NULL 2 100.00
Warnings:
Note 1003 /* select#1 */ select `test`.`t2`.`b` AS `b` from `test`.`t2` where <nop>(<in_optimizer>(`test`.`t2`.`b`,(/* select#2 */ select min(`test`.`t3`.`c`) from `test`.`t3`) <= <cache>(`test`.`t2`.`b`)))
select b from t2
where b >= any (select c from t3
group by (select a from t1 where a = 1) in
(select d from t4));
b
3
2
explain extended select b from t2
where b <= all (select c from t3
group by (select a from t1 where a = 1) in
(select d from t4));
id select_type table type possible_keys key key_len ref rows filtered Extra
1 PRIMARY t2 ALL NULL NULL NULL NULL 2 100.00 Using where
2 SUBQUERY t3 ALL NULL NULL NULL NULL 2 100.00
Warnings:
Note 1003 /* select#1 */ select `test`.`t2`.`b` AS `b` from `test`.`t2` where <not>(<in_optimizer>(`test`.`t2`.`b`,<min>(/* select#2 */ select `test`.`t3`.`c` from `test`.`t3`) < <cache>(`test`.`t2`.`b`)))
select b from t2
where b <= all (select c from t3
group by (select a from t1 where a = 1) in
(select d from t4));
b
2
drop table t1,t2,t3,t4;
# End of 10.3 tests
#
# MDEV-19134: EXISTS() slower if ORDER BY is defined

View File

@@ -2481,6 +2481,80 @@ eval $q3;
drop table t1,t2,t3;
--echo #
--echo # MDEV-29139: Redundant IN/ALL/ANY predicand in GROUP BY clause of
--echo # IN/ALL/ANY/EXISTS subquery
--echo #
create table t1 (a int);
create table t2 (b int);
create table t3 (c int);
create table t4 (d int);
insert into t1 values (3), (1);
insert into t2 values (3), (2);
insert into t3 values (4), (2);
insert into t4 values (1), (7);
let $q1=
select b from t2
where exists (select c from t3
group by (select a from t1 where a = 1) in (select d from t4));
eval explain extended $q1;
eval $q1;
eval prepare stmt from "$q1";
execute stmt;
execute stmt;
deallocate prepare stmt;
let $q2=
select b from t2
where exists (select c from t3
group by (select a from t1 where a = 1) >=
any (select d from t4));
eval explain extended $q2;
eval $q2;
let $q3=
select b from t2
where exists (select c from t3
group by (select a from t1 where a = 1) <
all (select d from t4));
eval explain extended $q3;
eval $q3;
let $q4=
select b from t2
where b in (select c from t3
group by (select a from t1 where a = 1) in (select d from t4));
eval explain extended $q4;
eval $q4;
let $q5=
select b from t2
where b >= any (select c from t3
group by (select a from t1 where a = 1) in
(select d from t4));
eval explain extended $q5;
eval $q5;
let $q6=
select b from t2
where b <= all (select c from t3
group by (select a from t1 where a = 1) in
(select d from t4));
eval explain extended $q6;
eval $q6;
drop table t1,t2,t3,t4;
--echo # End of 10.3 tests
--echo #

View File

@@ -14,7 +14,7 @@ connection node_1_u;
begin;
update user set j = j + 1 WHERE id > 0;
connection node_1_i;
set debug_sync='lock_wait_suspend_thread_enter SIGNAL ins_waiting WAIT_FOR cont_ins';
set debug_sync='lock_wait_start SIGNAL ins_waiting WAIT_FOR cont_ins';
insert into user_session(id,fk1,fk2) values (2, 2, 2);
connection node_1;
set debug_sync='now WAIT_FOR ins_waiting';
@@ -32,7 +32,7 @@ connection node_1_u;
begin;
update user set j = j + 1 WHERE id > 0;
connection node_1_i;
set debug_sync='lock_wait_suspend_thread_enter SIGNAL ins_waiting WAIT_FOR cont_ins';
set debug_sync='lock_wait_start SIGNAL ins_waiting WAIT_FOR cont_ins';
insert into user_session(id,fk1,fk2) values (2, 2, 2);
connection node_1;
set debug_sync='now WAIT_FOR ins_waiting';
@@ -50,7 +50,7 @@ connection node_1_u;
begin;
update user set j = j + 1 WHERE id > 0;
connection node_1_i;
set debug_sync='lock_wait_suspend_thread_enter SIGNAL ins_waiting WAIT_FOR cont_ins';
set debug_sync='lock_wait_start SIGNAL ins_waiting WAIT_FOR cont_ins';
insert into user_session(id,fk1,fk2) values (2, 2, 2);
connection node_1;
set debug_sync='now WAIT_FOR ins_waiting';
@@ -68,7 +68,7 @@ connection node_1_u;
begin;
update user set j = j + 1 WHERE id > 0;
connection node_1_i;
set debug_sync='lock_wait_suspend_thread_enter SIGNAL ins_waiting WAIT_FOR cont_ins';
set debug_sync='lock_wait_start SIGNAL ins_waiting WAIT_FOR cont_ins';
insert into user_session(id,fk1,fk2) values (2, 2, 2);
connection node_1;
set debug_sync='now WAIT_FOR ins_waiting';
@@ -86,7 +86,7 @@ connection node_1_u;
begin;
update user set j = j + 1 WHERE id > 0;
connection node_1_i;
set debug_sync='lock_wait_suspend_thread_enter SIGNAL ins_waiting WAIT_FOR cont_ins';
set debug_sync='lock_wait_start SIGNAL ins_waiting WAIT_FOR cont_ins';
insert into user_session(id,fk1,fk2) values (2, 2, 2);
connection node_1;
set debug_sync='now WAIT_FOR ins_waiting';
@@ -104,7 +104,7 @@ connection node_1_u;
begin;
update user set j = j + 1 WHERE id > 0;
connection node_1_i;
set debug_sync='lock_wait_suspend_thread_enter SIGNAL ins_waiting WAIT_FOR cont_ins';
set debug_sync='lock_wait_start SIGNAL ins_waiting WAIT_FOR cont_ins';
insert into user_session(id,fk1,fk2) values (2, 2, 2);
connection node_1;
set debug_sync='now WAIT_FOR ins_waiting';
@@ -122,7 +122,7 @@ connection node_1_u;
begin;
update user set j = j + 1 WHERE id > 0;
connection node_1_i;
set debug_sync='lock_wait_suspend_thread_enter SIGNAL ins_waiting WAIT_FOR cont_ins';
set debug_sync='lock_wait_start SIGNAL ins_waiting WAIT_FOR cont_ins';
insert into user_session(id,fk1,fk2) values (2, 2, 2);
connection node_1;
set debug_sync='now WAIT_FOR ins_waiting';
@@ -140,7 +140,7 @@ connection node_1_u;
begin;
update user set j = j + 1 WHERE id > 0;
connection node_1_i;
set debug_sync='lock_wait_suspend_thread_enter SIGNAL ins_waiting WAIT_FOR cont_ins';
set debug_sync='lock_wait_start SIGNAL ins_waiting WAIT_FOR cont_ins';
insert into user_session(id,fk1,fk2) values (2, 2, 2);
connection node_1;
set debug_sync='now WAIT_FOR ins_waiting';
@@ -158,7 +158,7 @@ connection node_1_u;
begin;
update user set j = j + 1 WHERE id > 0;
connection node_1_i;
set debug_sync='lock_wait_suspend_thread_enter SIGNAL ins_waiting WAIT_FOR cont_ins';
set debug_sync='lock_wait_start SIGNAL ins_waiting WAIT_FOR cont_ins';
insert into user_session(id,fk1,fk2) values (2, 2, 2);
connection node_1;
set debug_sync='now WAIT_FOR ins_waiting';
@@ -176,7 +176,7 @@ connection node_1_u;
begin;
update user set j = j + 1 WHERE id > 0;
connection node_1_i;
set debug_sync='lock_wait_suspend_thread_enter SIGNAL ins_waiting WAIT_FOR cont_ins';
set debug_sync='lock_wait_start SIGNAL ins_waiting WAIT_FOR cont_ins';
insert into user_session(id,fk1,fk2) values (2, 2, 2);
connection node_1;
set debug_sync='now WAIT_FOR ins_waiting';
@@ -202,7 +202,7 @@ connection node_1_u;
begin;
execute upd;
connection node_1_i;
set debug_sync='lock_wait_suspend_thread_enter SIGNAL ins_waiting WAIT_FOR cont_ins';
set debug_sync='lock_wait_start SIGNAL ins_waiting WAIT_FOR cont_ins';
execute ins1;
connection node_1;
set debug_sync='now WAIT_FOR ins_waiting';
@@ -220,7 +220,7 @@ connection node_1_u;
begin;
execute upd;
connection node_1_i;
set debug_sync='lock_wait_suspend_thread_enter SIGNAL ins_waiting WAIT_FOR cont_ins';
set debug_sync='lock_wait_start SIGNAL ins_waiting WAIT_FOR cont_ins';
execute ins1;
connection node_1;
set debug_sync='now WAIT_FOR ins_waiting';
@@ -238,7 +238,7 @@ connection node_1_u;
begin;
execute upd;
connection node_1_i;
set debug_sync='lock_wait_suspend_thread_enter SIGNAL ins_waiting WAIT_FOR cont_ins';
set debug_sync='lock_wait_start SIGNAL ins_waiting WAIT_FOR cont_ins';
execute ins1;
connection node_1;
set debug_sync='now WAIT_FOR ins_waiting';
@@ -256,7 +256,7 @@ connection node_1_u;
begin;
execute upd;
connection node_1_i;
set debug_sync='lock_wait_suspend_thread_enter SIGNAL ins_waiting WAIT_FOR cont_ins';
set debug_sync='lock_wait_start SIGNAL ins_waiting WAIT_FOR cont_ins';
execute ins1;
connection node_1;
set debug_sync='now WAIT_FOR ins_waiting';
@@ -274,7 +274,7 @@ connection node_1_u;
begin;
execute upd;
connection node_1_i;
set debug_sync='lock_wait_suspend_thread_enter SIGNAL ins_waiting WAIT_FOR cont_ins';
set debug_sync='lock_wait_start SIGNAL ins_waiting WAIT_FOR cont_ins';
execute ins1;
connection node_1;
set debug_sync='now WAIT_FOR ins_waiting';
@@ -292,7 +292,7 @@ connection node_1_u;
begin;
execute upd;
connection node_1_i;
set debug_sync='lock_wait_suspend_thread_enter SIGNAL ins_waiting WAIT_FOR cont_ins';
set debug_sync='lock_wait_start SIGNAL ins_waiting WAIT_FOR cont_ins';
execute ins1;
connection node_1;
set debug_sync='now WAIT_FOR ins_waiting';
@@ -310,7 +310,7 @@ connection node_1_u;
begin;
execute upd;
connection node_1_i;
set debug_sync='lock_wait_suspend_thread_enter SIGNAL ins_waiting WAIT_FOR cont_ins';
set debug_sync='lock_wait_start SIGNAL ins_waiting WAIT_FOR cont_ins';
execute ins1;
connection node_1;
set debug_sync='now WAIT_FOR ins_waiting';
@@ -328,7 +328,7 @@ connection node_1_u;
begin;
execute upd;
connection node_1_i;
set debug_sync='lock_wait_suspend_thread_enter SIGNAL ins_waiting WAIT_FOR cont_ins';
set debug_sync='lock_wait_start SIGNAL ins_waiting WAIT_FOR cont_ins';
execute ins1;
connection node_1;
set debug_sync='now WAIT_FOR ins_waiting';
@@ -346,7 +346,7 @@ connection node_1_u;
begin;
execute upd;
connection node_1_i;
set debug_sync='lock_wait_suspend_thread_enter SIGNAL ins_waiting WAIT_FOR cont_ins';
set debug_sync='lock_wait_start SIGNAL ins_waiting WAIT_FOR cont_ins';
execute ins1;
connection node_1;
set debug_sync='now WAIT_FOR ins_waiting';
@@ -364,7 +364,7 @@ connection node_1_u;
begin;
execute upd;
connection node_1_i;
set debug_sync='lock_wait_suspend_thread_enter SIGNAL ins_waiting WAIT_FOR cont_ins';
set debug_sync='lock_wait_start SIGNAL ins_waiting WAIT_FOR cont_ins';
execute ins1;
connection node_1;
set debug_sync='now WAIT_FOR ins_waiting';

View File

@@ -72,7 +72,7 @@ while($counter > 0)
update user set j = j + 1 WHERE id > 0;
--connection node_1_i
set debug_sync='lock_wait_suspend_thread_enter SIGNAL ins_waiting WAIT_FOR cont_ins';
set debug_sync='lock_wait_start SIGNAL ins_waiting WAIT_FOR cont_ins';
send insert into user_session(id,fk1,fk2) values (2, 2, 2);
--connection node_1
@@ -126,7 +126,7 @@ while($counter > 0)
#update user set j = j + 1 WHERE id > 0;
--connection node_1_i
set debug_sync='lock_wait_suspend_thread_enter SIGNAL ins_waiting WAIT_FOR cont_ins';
set debug_sync='lock_wait_start SIGNAL ins_waiting WAIT_FOR cont_ins';
send execute ins1;
--connection node_1

View File

@@ -7,12 +7,12 @@ SET DEBUG_SYNC = 'innodb_row_search_for_mysql_exit SIGNAL first_del_row_search_m
DELETE FROM t WHERE b = 20;
connect con_ins_1,localhost,root,,;
SET DEBUG_SYNC = 'now WAIT_FOR first_del_row_search_mvcc_finished';
SET DEBUG_SYNC = 'lock_wait_suspend_thread_enter SIGNAL first_ins_locked';
SET DEBUG_SYNC = 'lock_wait_start SIGNAL first_ins_locked';
SET DEBUG_SYNC = 'ib_after_row_insert SIGNAL first_ins_row_inserted WAIT_FOR first_ins_cont';
INSERT INTO t VALUES(10, 20);
connect con_del_2,localhost,root,,;
SET DEBUG_SYNC = 'now WAIT_FOR first_ins_locked';
SET DEBUG_SYNC = 'lock_wait_suspend_thread_enter SIGNAL second_del_locked';
SET DEBUG_SYNC = 'lock_wait_start SIGNAL second_del_locked';
DELETE FROM t WHERE b = 20;
connection default;
SET DEBUG_SYNC = 'now WAIT_FOR second_del_locked';

View File

@@ -0,0 +1,42 @@
CREATE TABLE t (a int PRIMARY KEY, b int) engine = InnoDB;
CREATE TABLE t2 (a int PRIMARY KEY) engine = InnoDB;
INSERT INTO t VALUES (10, 10), (20, 20), (30, 30);
INSERT INTO t2 VALUES (10), (20), (30);
BEGIN;
SELECT * FROM t WHERE a = 20 FOR UPDATE;
a b
20 20
connect con_2,localhost,root,,;
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
BEGIN;
SET DEBUG_SYNC = 'lock_trx_handle_wait_enter SIGNAL upd_locked WAIT_FOR upd_cont EXECUTE 2';
UPDATE t SET b = 100;
connect con_3,localhost,root,,;
BEGIN;
UPDATE t2 SET a = a + 100;
SELECT * FROM t WHERE a = 30 FOR UPDATE;
a b
30 30
SET DEBUG_SYNC='now WAIT_FOR upd_locked';
SET DEBUG_SYNC = 'lock_wait_start SIGNAL sel_locked';
SELECT * FROM t WHERE a = 20 FOR UPDATE;
connection default;
SET DEBUG_SYNC='now WAIT_FOR sel_locked';
ROLLBACK;
SET DEBUG_SYNC='now SIGNAL upd_cont';
SET innodb_lock_wait_timeout=1;
SET DEBUG_SYNC="now WAIT_FOR upd_locked";
SET DEBUG_SYNC="lock_wait_end SIGNAL upd_cont";
SELECT * FROM t WHERE a = 10 FOR UPDATE;
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
connection con_3;
a b
20 20
connection con_2;
ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
disconnect con_3;
disconnect con_2;
connection default;
SET DEBUG_SYNC = 'RESET';
DROP TABLE t;
DROP TABLE t2;

View File

@@ -11,6 +11,21 @@ CREATE TABLE `d255`.`_##################################################`
ERROR HY000: Long database name and identifier for object resulted in path length exceeding 512 characters. Path: './@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023/_@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023@0023
CREATE TABLE `d255`.`##################################################`
(a INT PRIMARY KEY, FOREIGN KEY(a) REFERENCES test.t(a)) ENGINE=InnoDB;
#
# MDEV-29258 Failing assertion for name length on RENAME TABLE
#
CREATE TABLE `d255`.`d245` (x INT) ENGINE=InnoDB;
DROP TABLE `d255`.`d250`;
RENAME TABLE `d250#`.`d245` TO `d250#`.`d250`;
RENAME TABLE `d255`.`d250` TO a;
DROP TABLE a,t;
#
# MDEV-29409 Buffer overflow in my_wc_mb_filename() on RENAME TABLE
#
CREATE TABLE `d255`.t(a INT PRIMARY KEY)ENGINE=InnoDB;
CREATE TABLE `d255`.u(a INT PRIMARY KEY,
CONSTRAINT `d320` FOREIGN KEY (a) REFERENCES `d255`.t (a)) ENGINE=InnoDB;
RENAME TABLE `d255`.u TO u;
DROP TABLE u;
DROP DATABASE `d255`;
DROP TABLE t;
# End of 10.3 tests

View File

@@ -38,7 +38,7 @@ select f1, f2 from t2 for update;
f1 f2
1 2
connection default;
set debug_sync='lock_wait_suspend_thread_enter SIGNAL upd_waiting WAIT_FOR go_upd';
set debug_sync='lock_wait_start SIGNAL upd_waiting WAIT_FOR go_upd';
update t1 set f1 = 10 where f1 = 2;
connection con1;
set debug_sync='now WAIT_FOR upd_waiting';
@@ -97,7 +97,7 @@ select f1, f2 from t2 for update;
f1 f2
1 91
connection default;
set debug_sync='lock_wait_suspend_thread_enter SIGNAL upd_waiting WAIT_FOR go_upd';
set debug_sync='lock_wait_start SIGNAL upd_waiting WAIT_FOR go_upd';
update t1 set f2 = 28 where f2 = 91;
connection con1;
set debug_sync='now WAIT_FOR upd_waiting';
@@ -164,7 +164,7 @@ select f1 from t3 for update;
f1
2
connection default;
set debug_sync='lock_wait_suspend_thread_enter SIGNAL upd_waiting WAIT_FOR go_upd';
set debug_sync='lock_wait_start SIGNAL upd_waiting WAIT_FOR go_upd';
update t1 set f1 = 10 where f1 = 2;
connection con1;
set debug_sync='now WAIT_FOR upd_waiting';
@@ -253,7 +253,7 @@ select f1 from t3 for update;
f1
2
connection default;
set debug_sync='lock_wait_suspend_thread_enter SIGNAL upd_waiting WAIT_FOR go_upd';
set debug_sync='lock_wait_start SIGNAL upd_waiting WAIT_FOR go_upd';
update t1 set f2 = 28 where f2 = 91;
connection con1;
set debug_sync='now WAIT_FOR upd_waiting';

View File

@@ -16,19 +16,19 @@ SET DEBUG_SYNC = 'innodb_row_search_for_mysql_exit SIGNAL first_del_row_search_m
--connect(con_ins_1,localhost,root,,)
SET DEBUG_SYNC = 'now WAIT_FOR first_del_row_search_mvcc_finished';
# It's supposed the following INSERT will be suspended just after
# lock_wait_suspend_thread_enter syncpoint, and will be awaken
# lock_wait_start syncpoint, and will be awaken
# after the previous DELETE commits. ib_after_row_insert will be executed
# after the INSERT is woken up. The previous DELETE will wait for
# first_del_cont signal before commit, and this signal will be sent later.
# So it's safe to use two signals in a row here, it's guaranted the first
# signal will be received before the second signal is sent.
SET DEBUG_SYNC = 'lock_wait_suspend_thread_enter SIGNAL first_ins_locked';
SET DEBUG_SYNC = 'lock_wait_start SIGNAL first_ins_locked';
SET DEBUG_SYNC = 'ib_after_row_insert SIGNAL first_ins_row_inserted WAIT_FOR first_ins_cont';
--send INSERT INTO t VALUES(10, 20)
--connect(con_del_2,localhost,root,,)
SET DEBUG_SYNC = 'now WAIT_FOR first_ins_locked';
SET DEBUG_SYNC = 'lock_wait_suspend_thread_enter SIGNAL second_del_locked';
SET DEBUG_SYNC = 'lock_wait_start SIGNAL second_del_locked';
###############################################################################
# This DELETE is locked by the previous DELETE, after that DELETE is
# committed, it will still be locked by the next INSERT on delete-marked

View File

@@ -0,0 +1,102 @@
--source include/have_innodb.inc
--source include/have_debug_sync.inc
--source include/count_sessions.inc
CREATE TABLE t (a int PRIMARY KEY, b int) engine = InnoDB;
CREATE TABLE t2 (a int PRIMARY KEY) engine = InnoDB;
INSERT INTO t VALUES (10, 10), (20, 20), (30, 30);
INSERT INTO t2 VALUES (10), (20), (30);
BEGIN; # trx 1
SELECT * FROM t WHERE a = 20 FOR UPDATE;
# Locking order:
# (10,10) (20,20) (30,30)
# ^
# trx 1
--connect(con_2,localhost,root,,)
# RC is neccessary to do semi-consistent read
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
BEGIN; # trx 2
# The first time it will be hit on trying to lock (20,20), the second hit
# will be on (30,30).
SET DEBUG_SYNC = 'lock_trx_handle_wait_enter SIGNAL upd_locked WAIT_FOR upd_cont EXECUTE 2';
# We must not modify primary key fields to cause rr_sequential() read record
# function choosing in mysql_update(), i.e. both query_plan.using_filesort and
# query_plan.using_io_buffer must be false during init_read_record() call.
--send UPDATE t SET b = 100
--connect(con_3,localhost,root,,)
BEGIN; # trx 3
# The following update is necessary to increase the transaction weight, which is
# calculated as the number of locks + the number of undo records during deadlock
# report. Victim's transaction should have minimum weight. We need trx 2 to be
# choosen as victim, that's why we need to increase the current transaction
# weight.
UPDATE t2 SET a = a + 100;
SELECT * FROM t WHERE a = 30 FOR UPDATE;
SET DEBUG_SYNC='now WAIT_FOR upd_locked';
# Locking queue:
# (10,10) (20,20) (30,30)
# ^ ^ ^
# trx 2 trx 1 trx 3
# trx 2 (waiting for 1)
SET DEBUG_SYNC = 'lock_wait_start SIGNAL sel_locked';
--send SELECT * FROM t WHERE a = 20 FOR UPDATE
--connection default
SET DEBUG_SYNC='now WAIT_FOR sel_locked';
# Locking queue:
# (10,10) (20,20) (30,30)
# ^ ^ ^
# trx 2 trx 1 trx 3
# trx 2 (waiting for 1)
# trx 3 (waiting for 1)
#
# Note trx 1 must grant lock to trx2 before trx 2 checks the lock state in
# lock_trx_handle_wait(), i.e. the function must return DB_SUCCESS, that's why
# the following ROLLBACK must be executed before sending upd_cont signal.
ROLLBACK;
SET DEBUG_SYNC='now SIGNAL upd_cont';
SET innodb_lock_wait_timeout=1;
SET DEBUG_SYNC="now WAIT_FOR upd_locked";
# Locking queue:
# (10,10) (20,20) (30,30)
# ^ ^ ^
# trx 2 trx 2 trx 3
# trx 3 (waiting for 2) trx 2 (waiting for 3)
#
# Deadlock happened after trx 1 granted lock to trx 2, and trx2 continued
# sequential read (with rr_sequential() read record function), and requested
# lock on (30,30). But the deadlock has not been determined yet.
SET DEBUG_SYNC="lock_wait_end SIGNAL upd_cont";
--error ER_LOCK_WAIT_TIMEOUT
# The deadlock will be determined in lock_wait() after lock wait timeout
# expired.
SELECT * FROM t WHERE a = 10 FOR UPDATE;
--connection con_3
--reap
--connection con_2
# As lock_trx_handle_wait() wrongly returned DB_SUCCESS instead of
# DB_DEADLOCK, row_search_mvcc() of trx 2 behaves so as if (30,30) was locked.
# But the waiting(for trx 3) lock was cancelled by deadlock checker after
# trx 2 was choosen as a victim (see lock_cancel_waiting_and_release() call
# from Deadlock::report() for details). The try to update non-locked record
# will cause assertion if the bug is not fixed.
--error ER_LOCK_DEADLOCK
--reap
--disconnect con_3
--disconnect con_2
--connection default
SET DEBUG_SYNC = 'RESET';
DROP TABLE t;
DROP TABLE t2;
--source include/wait_until_count_sessions.inc

View File

@@ -38,8 +38,40 @@ eval CREATE TABLE `$d255`.`_$d250`
--replace_result $d255 d255
eval CREATE TABLE `$d255`.`$d250`
(a INT PRIMARY KEY, FOREIGN KEY(a) REFERENCES test.t(a)) ENGINE=InnoDB;
--echo #
--echo # MDEV-29258 Failing assertion for name length on RENAME TABLE
--echo #
let $d245=-------------------------------------------------;
--replace_result $d245 d245 $d255 d255
eval CREATE TABLE `$d255`.`$d245` (x INT) ENGINE=InnoDB;
--replace_result $d250 d250 $d255 d255
eval DROP TABLE `$d255`.`$d250`;
--replace_result $d245 d245 $d250 d250 d255 d255
eval RENAME TABLE `$d255`.`$d245` TO `$d255`.`$d250`;
--replace_result $d250 d250 $d255 d255
eval RENAME TABLE `$d255`.`$d250` TO a;
--replace_result $d255 d255
DROP TABLE a,t;
--echo #
--echo # MDEV-29409 Buffer overflow in my_wc_mb_filename() on RENAME TABLE
--echo #
let $d225=#############################################;
let $d320=################################################################;
--replace_result $d255 d255
eval CREATE TABLE `$d255`.t(a INT PRIMARY KEY)ENGINE=InnoDB;
--replace_result $d255 d255 $d320 d320
eval CREATE TABLE `$d255`.u(a INT PRIMARY KEY,
CONSTRAINT `$d320` FOREIGN KEY (a) REFERENCES `$d255`.t (a)) ENGINE=InnoDB;
--replace_result $d255 d255
eval RENAME TABLE `$d255`.u TO u;
DROP TABLE u;
--replace_result $d255 d255
eval DROP DATABASE `$d255`;
DROP TABLE t;
--echo # End of 10.3 tests

View File

@@ -28,7 +28,7 @@ start transaction;
select f1, f2 from t2 for update;
connection default;
set debug_sync='lock_wait_suspend_thread_enter SIGNAL upd_waiting WAIT_FOR go_upd';
set debug_sync='lock_wait_start SIGNAL upd_waiting WAIT_FOR go_upd';
send update t1 set f1 = 10 where f1 = 2;
connection con1;
@@ -72,7 +72,7 @@ start transaction;
select f1, f2 from t2 for update;
connection default;
set debug_sync='lock_wait_suspend_thread_enter SIGNAL upd_waiting WAIT_FOR go_upd';
set debug_sync='lock_wait_start SIGNAL upd_waiting WAIT_FOR go_upd';
send update t1 set f2 = 28 where f2 = 91;
connection con1;
@@ -120,7 +120,7 @@ start transaction;
select f1 from t3 for update;
connection default;
set debug_sync='lock_wait_suspend_thread_enter SIGNAL upd_waiting WAIT_FOR go_upd';
set debug_sync='lock_wait_start SIGNAL upd_waiting WAIT_FOR go_upd';
send update t1 set f1 = 10 where f1 = 2;
connection con1;
@@ -183,7 +183,7 @@ start transaction;
select f1 from t3 for update;
connection default;
set debug_sync='lock_wait_suspend_thread_enter SIGNAL upd_waiting WAIT_FOR go_upd';
set debug_sync='lock_wait_start SIGNAL upd_waiting WAIT_FOR go_upd';
send update t1 set f2 = 28 where f2 = 91;
connection con1;

View File

@@ -1,4 +1,5 @@
INSTALL PLUGIN simple_parser SONAME 'mypluglib';
FLUSH TABLES;
# Test Part 1: Grammar Test
CREATE TABLE articles (
id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY,
@@ -31,7 +32,7 @@ INSERT INTO articles (title, body) VALUES
('1001 MySQL Tricks','How to use full-text search engine'),
('Go MySQL Tricks','How to use full text search engine');
SELECT * FROM articles WHERE
MATCH(title, body) AGAINST('mysql');
MATCH(title, body) AGAINST('mysql') ORDER BY id;
id title body
1 MySQL Tutorial DBMS stands for MySQL DataBase ...
2 How To Use MySQL Well After you went through a ...
@@ -68,7 +69,7 @@ INSERT INTO articles (title, body) VALUES
('Go MySQL Tricks','How to use full text search engine');
ALTER TABLE articles ADD FULLTEXT INDEX (title, body) WITH PARSER simple_parser;
SELECT * FROM articles WHERE
MATCH(title, body) AGAINST('mysql');
MATCH(title, body) AGAINST('mysql') ORDER BY id;
id title body
1 MySQL Tutorial DBMS stands for MySQL DataBase ...
2 How To Use MySQL Well After you went through a ...
@@ -88,21 +89,23 @@ MATCH(title, body) AGAINST('full text');
id title body
5 Go MySQL Tricks How to use full text search engine
SELECT * FROM articles WHERE
MATCH(title, body) AGAINST('full-text' WITH QUERY EXPANSION);
MATCH(title, body) AGAINST('full-text' WITH QUERY EXPANSION)
ORDER BY id;
id title body
1 MySQL Tutorial DBMS stands for MySQL DataBase ...
2 How To Use MySQL Well After you went through a ...
3 Optimizing MySQL In this tutorial we will show ...
4 1001 MySQL Tricks How to use full-text search engine
5 Go MySQL Tricks How to use full text search engine
2 How To Use MySQL Well After you went through a ...
1 MySQL Tutorial DBMS stands for MySQL DataBase ...
3 Optimizing MySQL In this tutorial we will show ...
SELECT * FROM articles WHERE
MATCH(title, body) AGAINST('full text' WITH QUERY EXPANSION);
MATCH(title, body) AGAINST('full text' WITH QUERY EXPANSION)
ORDER BY id;
id title body
5 Go MySQL Tricks How to use full text search engine
4 1001 MySQL Tricks How to use full-text search engine
2 How To Use MySQL Well After you went through a ...
1 MySQL Tutorial DBMS stands for MySQL DataBase ...
2 How To Use MySQL Well After you went through a ...
3 Optimizing MySQL In this tutorial we will show ...
4 1001 MySQL Tricks How to use full-text search engine
5 Go MySQL Tricks How to use full text search engine
SELECT * FROM articles WHERE
MATCH(title, body) AGAINST('"mysql database"' IN BOOLEAN MODE);
id title body
@@ -138,27 +141,27 @@ INSERT INTO articles (title, body) VALUES
('Go MariaDB Tricks','How to use full text search engine');
# restart
SELECT * FROM articles WHERE
MATCH(title, body) AGAINST('MySQL');
MATCH(title, body) AGAINST('MySQL') ORDER BY id;
id title body
1 MySQL Tutorial DBMS stands for MySQL DataBase ...
2 How To Use MySQL Well After you went through a ...
3 Optimizing MySQL In this tutorial we will show ...
4 1001 MySQL Tricks How to use full-text search engine
SELECT * FROM articles WHERE
MATCH(title, body) AGAINST('tutorial');
MATCH(title, body) AGAINST('tutorial') ORDER BY id;
id title body
1 MySQL Tutorial DBMS stands for MySQL DataBase ...
3 Optimizing MySQL In this tutorial we will show ...
SELECT * FROM articles WHERE
MATCH(title, body) AGAINST('Tricks');
MATCH(title, body) AGAINST('Tricks') ORDER BY id;
id title body
4 1001 MySQL Tricks How to use full-text search engine
5 Go MariaDB Tricks How to use full text search engine
SELECT * FROM articles WHERE
MATCH(title, body) AGAINST('full text search');
MATCH(title, body) AGAINST('full text search') ORDER BY id;
id title body
5 Go MariaDB Tricks How to use full text search engine
4 1001 MySQL Tricks How to use full-text search engine
5 Go MariaDB Tricks How to use full text search engine
SELECT COUNT(*) FROM articles;
COUNT(*)
5
@@ -186,7 +189,8 @@ UNINSTALL PLUGIN simple_parser;
Warnings:
Warning 1620 Plugin is busy and will be uninstalled on shutdown
SELECT * FROM articles WHERE
MATCH(title, body) AGAINST('mysql');
MATCH(title, body) AGAINST('mysql')
ORDER BY id;
id title body
1 MySQL Tutorial DBMS stands for MySQL DataBase ...
2 How To Use MySQL Well After you went through a ...

View File

@@ -6,6 +6,9 @@
# Install fts parser plugin
INSTALL PLUGIN simple_parser SONAME 'mypluglib';
# Flush the table mysql.plugin in case the server shutdown would time out.
FLUSH TABLES;
-- echo # Test Part 1: Grammar Test
# Create a myisam table and alter it to innodb table
CREATE TABLE articles (
@@ -52,7 +55,7 @@ INSERT INTO articles (title, body) VALUES
# Simple term search
SELECT * FROM articles WHERE
MATCH(title, body) AGAINST('mysql');
MATCH(title, body) AGAINST('mysql') ORDER BY id;
# Test stopword and word len less than fts_min_token_size
SELECT * FROM articles WHERE
@@ -90,7 +93,7 @@ ALTER TABLE articles ADD FULLTEXT INDEX (title, body) WITH PARSER simple_parser;
# Simple term search
SELECT * FROM articles WHERE
MATCH(title, body) AGAINST('mysql');
MATCH(title, body) AGAINST('mysql') ORDER BY id;
# Test stopword and word len less than fts_min_token_size
SELECT * FROM articles WHERE
@@ -105,10 +108,12 @@ SELECT * FROM articles WHERE
# Test query expansion
SELECT * FROM articles WHERE
MATCH(title, body) AGAINST('full-text' WITH QUERY EXPANSION);
MATCH(title, body) AGAINST('full-text' WITH QUERY EXPANSION)
ORDER BY id;
SELECT * FROM articles WHERE
MATCH(title, body) AGAINST('full text' WITH QUERY EXPANSION);
MATCH(title, body) AGAINST('full text' WITH QUERY EXPANSION)
ORDER BY id;
# No result here, we get '"mysql' 'database"' by simple parser
SELECT * FROM articles WHERE
@@ -152,13 +157,13 @@ INSERT INTO articles (title, body) VALUES
--source include/restart_mysqld.inc
SELECT * FROM articles WHERE
MATCH(title, body) AGAINST('MySQL');
MATCH(title, body) AGAINST('MySQL') ORDER BY id;
SELECT * FROM articles WHERE
MATCH(title, body) AGAINST('tutorial');
MATCH(title, body) AGAINST('tutorial') ORDER BY id;
SELECT * FROM articles WHERE
MATCH(title, body) AGAINST('Tricks');
MATCH(title, body) AGAINST('Tricks') ORDER BY id;
SELECT * FROM articles WHERE
MATCH(title, body) AGAINST('full text search');
MATCH(title, body) AGAINST('full text search') ORDER BY id;
SELECT COUNT(*) FROM articles;
INSERT INTO articles (title, body) VALUES ('111', '1234 1234 1234');
@@ -195,7 +200,8 @@ UNINSTALL PLUGIN simple_parser;
# Simple term search
SELECT * FROM articles WHERE
MATCH(title, body) AGAINST('mysql');
MATCH(title, body) AGAINST('mysql')
ORDER BY id;
# Test stopword and word len less than fts_min_token_size
SELECT * FROM articles WHERE

View File

@@ -3,4 +3,12 @@ FOUND 1 /missing required privilege RELOAD/ in backup.log
FOUND 1 /missing required privilege PROCESS/ in backup.log
FOUND 1 /GRANT USAGE ON/ in backup.log
GRANT RELOAD, PROCESS on *.* to backup@localhost;
NOT FOUND /missing required privilege REPLICA MONITOR/ in backup.log
GRANT REPLICA MONITOR ON *.* TO backup@localhost;
REVOKE REPLICA MONITOR ON *.* FROM backup@localhost;
GRANT CONNECTION ADMIN ON *.* TO backup@localhost;
FOUND 1 /missing required privilege REPLICATION SLAVE ADMIN/ in backup.log
NOT FOUND /missing required privilege REPLICA MONITOR/ in backup.log
GRANT REPLICATION SLAVE ADMIN ON *.* TO backup@localhost;
GRANT REPLICA MONITOR ON *.* TO backup@localhost;
DROP USER backup@localhost;

View File

@@ -25,7 +25,62 @@ GRANT RELOAD, PROCESS on *.* to backup@localhost;
--disable_result_log
exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --backup -ubackup --target-dir=$targetdir;
--enable_result_log
rmdir $targetdir;
# MDEV-23607 Warning: missing required privilege REPLICATION CLIENT
# --slave-info and galera info require REPLICA MONITOR
--disable_result_log
error 1;
exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --backup -ubackup --slave-info --target-dir=$targetdir > $MYSQLTEST_VARDIR/tmp/backup.log;
--enable_result_log
rmdir $targetdir;
--let SEARCH_PATTERN= missing required privilege REPLICA MONITOR
--source include/search_pattern_in_file.inc
GRANT REPLICA MONITOR ON *.* TO backup@localhost;
--disable_result_log
exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --backup -ubackup --slave-info --target-dir=$targetdir;
--enable_result_log
rmdir $targetdir;
REVOKE REPLICA MONITOR ON *.* FROM backup@localhost;
# TODO need a query that would delay a BACKUP STAGE START/ BACKUP STAGE BLOCK_COMMIT longer than the kill-long-queries-timeout
#--send SELECT SLEEP(9) kill_me
## kill-long-query-type=(not empty) requires CONNECTION ADMIN
#--disable_result_log
#error 1;
#--exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --backup -ubackup --kill-long-query-type=all --kill-long-queries-timeout=4 --target-dir=$targetdir > $MYSQLTEST_VARDIR/tmp/backup.log;
#--reap
#--enable_result_log
#rmdir $targetdir;
#
#--let SEARCH_PATTERN= missing required privilege CONNECTION ADMIN
#--source include/search_pattern_in_file.inc
GRANT CONNECTION ADMIN ON *.* TO backup@localhost;
--disable_result_log
exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --backup -ubackup --kill-long-query-type=all --kill-long-queries-timeout=1 --target-dir=$targetdir;
--enable_result_log
rmdir $targetdir;
# --safe-slave-backup requires REPLICATION SLAVE ADMIN, and REPLICA MONITOR
--disable_result_log
error 1;
exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --backup -ubackup --safe-slave-backup --target-dir=$targetdir > $MYSQLTEST_VARDIR/tmp/backup.log;
--enable_result_log
rmdir $targetdir;
--let SEARCH_PATTERN= missing required privilege REPLICATION SLAVE ADMIN
--source include/search_pattern_in_file.inc
--let SEARCH_PATTERN= missing required privilege REPLICA MONITOR
--source include/search_pattern_in_file.inc
GRANT REPLICATION SLAVE ADMIN ON *.* TO backup@localhost;
GRANT REPLICA MONITOR ON *.* TO backup@localhost;
--disable_result_log
exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --backup -ubackup --safe-slave-backup --target-dir=$targetdir;
--enable_result_log
rmdir $targetdir;
DROP USER backup@localhost;
# Cleanup
rmdir $targetdir;

View File

@@ -191,6 +191,20 @@ ERROR 23000: Duplicate entry '1-2020-03-01-2020-03-02' for key 'PRIMARY'
alter table t1 add system versioning;
drop table t1;
#
# MDEV-18873 Server crashes in Compare_identifiers::operator or in
# my_strcasecmp_utf8 upon ADD PERIOD IF NOT EXISTS with empty name
#
alter table t add period if not exists for `` (s,e);
ERROR 42000: Incorrect column name ''
create table t(s DATE, e DATE);
alter table t add period if not exists for `` (s,e);
ERROR 42000: Incorrect column name ''
alter table t add period if not exists for ` ` (s,e);
ERROR 42000: Incorrect column name ' '
create table t2 (period for `` (s,e)) select * from t;
ERROR 42000: Incorrect column name ''
drop table t;
#
# MDEV-21941 RENAME doesn't work for system time or period fields
#
create or replace table t1 (

View File

@@ -152,6 +152,29 @@ alter table t1 add system versioning;
# cleanup
drop table t1;
--echo #
--echo # MDEV-18873 Server crashes in Compare_identifiers::operator or in
--echo # my_strcasecmp_utf8 upon ADD PERIOD IF NOT EXISTS with empty name
--echo #
# When there is no table defined.
--error ER_WRONG_COLUMN_NAME
alter table t add period if not exists for `` (s,e);
# When there is an actual table.
create table t(s DATE, e DATE);
--error ER_WRONG_COLUMN_NAME
alter table t add period if not exists for `` (s,e);
# When the last character is space
--error ER_WRONG_COLUMN_NAME
alter table t add period if not exists for ` ` (s,e);
# Create table with an empty period name
--error ER_WRONG_COLUMN_NAME
create table t2 (period for `` (s,e)) select * from t;
drop table t;
--echo #
--echo # MDEV-21941 RENAME doesn't work for system time or period fields
--echo #

View File

@@ -0,0 +1,55 @@
include/master-slave.inc
[connection master]
#
# Set replica to ignore system mysql tables
connection slave;
include/stop_slave.inc
SET @@GLOBAL.replicate_wild_ignore_table="mysql.%";
include/start_slave.inc
#
# Execute grant-based commands on primary which modify mysql system
# tables
connection master;
CREATE ROLE journalist;
CREATE USER testuser@localhost IDENTIFIED by '';
GRANT journalist to testuser@localhost;
#
# Execute SET commands which use the previous user/role data
SET DEFAULT ROLE journalist for testuser@localhost;
SET PASSWORD for testuser@localhost= PASSWORD('123');
include/save_master_gtid.inc
#
# Verify primary's grant tables have the correct user/role data
select count(*)=1 from mysql.user where User='testuser';
count(*)=1
1
select count(*)=1 from mysql.roles_mapping where User='testuser';
count(*)=1
1
#
# Ensure that the replica receives all of the primary's events without
# error
connection slave;
include/sync_with_master_gtid.inc
Last_SQL_Error =
Last_SQL_Errno = 0
#
# Verify that the replica did not execute the master's commands
select count(*)=0 from mysql.user where User='testuser';
count(*)=0
1
select count(*)=0 from mysql.roles_mapping where User='testuser';
count(*)=0
1
#
# Clean up
connection master;
DROP ROLE journalist;
DROP USER testuser@localhost;
include/save_master_gtid.inc
connection slave;
include/sync_with_master_gtid.inc
include/stop_slave.inc
SET @@GLOBAL.replicate_wild_ignore_table="";
include/start_slave.inc
include/rpl_end.inc

View File

@@ -0,0 +1,83 @@
#
# Purpose:
# This test ensures that the SET DEFAULT ROLE and SET PASSWORD commands can
# be ignored by replica filter rules. MDEV-28294 exposed a bug in which
# SET DEFAULT ROLE would check for the existence of the given roles/user even
# when the targeted tables are ignored, resulting in errors if the targeted
# data does not exist. More specifically, when previously issued
# CREATE USER/ROLE commands are ignored by the replica because of the
# replication filtering rules, SET DEFAULT ROLE would result in an error
# because the targeted data does not exist.
#
# Methodology:
# Using a replica configured with replicate_wild_ignore_table="mysql.%",
# execute SET DEFAULT ROLE and SET PASSWORD on the primary and ensure that the
# replica neither errors nor executes the commands which the primary sends.
#
# References:
# MDEV-28294: set default role bypasses Replicate_Wild_Ignore_Table: mysql.%
#
source include/master-slave.inc;
source include/have_binlog_format_mixed.inc;
--echo #
--echo # Set replica to ignore system mysql tables
connection slave;
let $old_filter= query_get_value(SHOW SLAVE STATUS, Replicate_Wild_Ignore_Table, 1);
source include/stop_slave.inc;
SET @@GLOBAL.replicate_wild_ignore_table="mysql.%";
source include/start_slave.inc;
--echo #
--echo # Execute grant-based commands on primary which modify mysql system
--echo # tables
connection master;
CREATE ROLE journalist;
CREATE USER testuser@localhost IDENTIFIED by '';
GRANT journalist to testuser@localhost;
--echo #
--echo # Execute SET commands which use the previous user/role data
SET DEFAULT ROLE journalist for testuser@localhost;
SET PASSWORD for testuser@localhost= PASSWORD('123');
--source include/save_master_gtid.inc
--echo #
--echo # Verify primary's grant tables have the correct user/role data
select count(*)=1 from mysql.user where User='testuser';
select count(*)=1 from mysql.roles_mapping where User='testuser';
--echo #
--echo # Ensure that the replica receives all of the primary's events without
--echo # error
connection slave;
--source include/sync_with_master_gtid.inc
let $error= query_get_value(SHOW SLAVE STATUS, Last_SQL_Error, 1);
--echo Last_SQL_Error = $error
let $errno= query_get_value(SHOW SLAVE STATUS, Last_SQL_Errno, 1);
--echo Last_SQL_Errno = $errno
--echo #
--echo # Verify that the replica did not execute the master's commands
select count(*)=0 from mysql.user where User='testuser';
select count(*)=0 from mysql.roles_mapping where User='testuser';
--echo #
--echo # Clean up
# The master has to drop the role/user combination while the slave still has
# its filters active; otherwise, the slave would try to drop users/roles that
# were never replicated.
--connection master
DROP ROLE journalist;
DROP USER testuser@localhost;
--source include/save_master_gtid.inc
--connection slave
--source include/sync_with_master_gtid.inc
source include/stop_slave.inc;
--eval SET @@GLOBAL.replicate_wild_ignore_table="$old_filter"
source include/start_slave.inc;
--source include/rpl_end.inc

View File

@@ -92,7 +92,7 @@ extern "C" FILE *my_win_popen(const char *cmd, const char *mode)
goto error;
break;
default:
/* Unknown mode, éxpected "r", "rt", "w", "wt" */
/* Unknown mode, expected "r", "rt", "w", "wt" */
abort();
}
if (!SetHandleInformation(parent_pipe_end, HANDLE_FLAG_INHERIT, 0))

View File

@@ -392,7 +392,8 @@ bool Item_subselect::mark_as_eliminated_processor(void *arg)
bool Item_subselect::eliminate_subselect_processor(void *arg)
{
unit->item= NULL;
unit->exclude();
if (!unit->is_excluded())
unit->exclude();
eliminated= TRUE;
return FALSE;
}

View File

@@ -1,5 +1,5 @@
/* Copyright (c) 2000, 2018, Oracle and/or its affiliates.
Copyright (c) 2009, 2021, MariaDB
Copyright (c) 2009, 2022, MariaDB
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
@@ -1937,10 +1937,17 @@ class Grant_tables
public:
Grant_tables() : p_user_table(&m_user_table_json) { }
int open_and_lock(THD *thd, int which_tables, enum thr_lock_type lock_type)
/**
An auxiliary to build a list of involved tables.
@retval 0 Success
@retval -1 A my_error reported error
*/
int build_table_list(THD *thd, TABLE_LIST** ptr_first,
int which_tables, enum thr_lock_type lock_type,
TABLE_LIST *tables)
{
DBUG_ENTER("Grant_tables::open_and_lock");
TABLE_LIST tables[USER_TABLE+1], *first= NULL;
DBUG_ENTER("Grant_tables::build_table_list");
DBUG_ASSERT(which_tables); /* At least one table must be opened. */
/*
@@ -1965,12 +1972,23 @@ class Grant_tables
tl->updating= lock_type >= TL_FIRST_WRITE;
if (i >= FIRST_OPTIONAL_TABLE)
tl->open_strategy= TABLE_LIST::OPEN_IF_EXISTS;
tl->next_global= tl->next_local= first;
first= tl;
tl->next_global= tl->next_local= *ptr_first;
*ptr_first= tl;
}
else
tl->table= NULL;
}
DBUG_RETURN(0);
}
int open_and_lock(THD *thd, int which_tables, enum thr_lock_type lock_type)
{
DBUG_ENTER("Grant_tables::open_and_lock");
TABLE_LIST tables[USER_TABLE+1], *first= NULL;
if (build_table_list(thd, &first, which_tables, lock_type, tables))
DBUG_RETURN(-1);
uint counter;
int res= really_open(thd, first, &counter);
@@ -2041,6 +2059,48 @@ class Grant_tables
inline const Roles_mapping_table& roles_mapping_table() const
{ return m_roles_mapping_table; }
#ifdef HAVE_REPLICATION
/**
Checks if the tables targeted by a grant command should be ignored because
of the configured replication filters
@retval 1 Tables are excluded for replication
@retval 0 tables are included for replication
*/
int rpl_ignore_tables(THD *thd, TABLE_LIST* tables, int which_tables= 0,
enum thr_lock_type lock_type= TL_IGNORE)
{
DBUG_ENTER("Grant_tables::rpl_ignore_tables");
if (!(thd->slave_thread && !thd->spcont))
DBUG_RETURN(0);
TABLE_LIST all_tables[USER_TABLE+1];
if (!tables)
{
int rc __attribute__((unused))=
build_table_list(thd, &tables, which_tables, lock_type, all_tables);
DBUG_ASSERT(!rc); // Grant_tables must be already initialized
DBUG_ASSERT(tables);
}
if (tables->lock_type >= TL_FIRST_WRITE)
{
/*
GRANT and REVOKE are applied the slave in/exclusion rules as they are
some kind of updates to the mysql.% tables.
*/
Rpl_filter *rpl_filter= thd->system_thread_info.rpl_sql_info->rpl_filter;
if (rpl_filter->is_on() && !rpl_filter->tables_ok(0, tables))
DBUG_RETURN(1);
}
DBUG_RETURN(0);
}
#endif
private:
/* Before any operation is possible on grant tables, they must be opened.
@@ -2054,16 +2114,9 @@ class Grant_tables
{
DBUG_ENTER("Grant_tables::really_open:");
#ifdef HAVE_REPLICATION
if (tables->lock_type >= TL_FIRST_WRITE &&
thd->slave_thread && !thd->spcont)
if (rpl_ignore_tables(thd, tables))
{
/*
GRANT and REVOKE are applied the slave in/exclusion rules as they are
some kind of updates to the mysql.% tables.
*/
Rpl_filter *rpl_filter= thd->system_thread_info.rpl_sql_info->rpl_filter;
if (rpl_filter->is_on() && !rpl_filter->tables_ok(0, tables))
DBUG_RETURN(1);
DBUG_RETURN(1);
}
#endif
if (open_tables(thd, &tables, counter, MYSQL_LOCK_IGNORE_TIMEOUT))
@@ -4080,6 +4133,17 @@ int acl_check_set_default_role(THD *thd, const char *host, const char *user,
const char *role)
{
DBUG_ENTER("acl_check_set_default_role");
#ifdef HAVE_REPLICATION
/*
If the roles_mapping table is excluded by the replication filter, we return
successful without validating the user/role data because the command will
be ignored in a later call to `acl_set_default_role()` for a graceful exit.
*/
Grant_tables tables;
TABLE_LIST* first= NULL;
if (tables.rpl_ignore_tables(thd, first, Table_roles_mapping, TL_WRITE))
DBUG_RETURN(0);
#endif
DBUG_RETURN(check_alter_user(thd, host, user) ||
check_user_can_set_role(thd, user, host, NULL, role, NULL));
}

View File

@@ -36,6 +36,7 @@
#include "sql_limit.h" // Select_limit_counters
#include "json_table.h" // Json_table_column
#include "sql_schema.h"
#include "table.h"
/* Used for flags of nesting constructs */
#define SELECT_NESTING_MAP_SIZE 64
@@ -4562,6 +4563,11 @@ public:
int add_period(Lex_ident name, Lex_ident_sys_st start, Lex_ident_sys_st end)
{
if (check_period_name(name.str)) {
my_error(ER_WRONG_COLUMN_NAME, MYF(0), name.str);
return 1;
}
if (lex_string_cmp(system_charset_info, &start, &end) == 0)
{
my_error(ER_FIELD_SPECIFIED_TWICE, MYF(0), start.str);

View File

@@ -5069,7 +5069,7 @@ mysql_rename_table(handlerton *base, const LEX_CSTRING *old_db,
length= build_table_filename(to, sizeof(to) - 1, new_db->str,
new_name->str, "", flags & FN_TO_IS_TMP);
// Check if we hit FN_REFLEN bytes along with file extension.
if (length+reg_ext_length >= FN_REFLEN)
if (length+reg_ext_length > FN_REFLEN)
{
my_error(ER_IDENT_CAUSES_TOO_LONG_PATH, MYF(0), (int) sizeof(to)-1, to);
DBUG_RETURN(TRUE);

View File

@@ -4926,7 +4926,8 @@ void update_create_info_from_table(HA_CREATE_INFO *create_info, TABLE *table)
int
rename_file_ext(const char * from,const char * to,const char * ext)
{
char from_b[FN_REFLEN],to_b[FN_REFLEN];
/* Reserve space for ./databasename/tablename.frm + NUL byte */
char from_b[2 + FN_REFLEN + 4 + 1], to_b[2 + FN_REFLEN + 4 + 1];
(void) strxmov(from_b,from,ext,NullS);
(void) strxmov(to_b,to,ext,NullS);
return mysql_file_rename(key_file_frm, from_b, to_b, MYF(0));
@@ -5181,6 +5182,12 @@ bool check_column_name(const char *name)
}
bool check_period_name(const char *name)
{
return check_column_name(name);
}
/**
Checks whether a table is intact. Should be done *just* after the table has
been opened.

View File

@@ -3223,6 +3223,7 @@ void open_table_error(TABLE_SHARE *share, enum open_frm_error error,
void update_create_info_from_table(HA_CREATE_INFO *info, TABLE *form);
bool check_db_name(LEX_STRING *db);
bool check_column_name(const char *name);
bool check_period_name(const char *name);
bool check_table_name(const char *name, size_t length, bool check_for_path_chars);
int rename_file_ext(const char * from,const char * to,const char * ext);
char *get_field(MEM_ROOT *mem, Field *field);

View File

@@ -40,6 +40,8 @@ struct Compare_identifiers
{
int operator()(const LEX_CSTRING& a, const LEX_CSTRING& b) const
{
DBUG_ASSERT(a.str != NULL);
DBUG_ASSERT(b.str != NULL);
DBUG_ASSERT(a.str[a.length] == 0);
DBUG_ASSERT(b.str[b.length] == 0);
return my_strcasecmp(system_charset_info, a.str, b.str);

View File

@@ -642,7 +642,6 @@ bool DOMNODELIST::DropItem(PGLOBAL g, int n)
if (Listp == NULL || Listp->length < n)
return true;
//Listp->item[n] = NULL; La propriété n'a pas de méthode 'set'
return false;
} // end of DeleteItem

View File

@@ -530,8 +530,7 @@ btr_page_alloc_low(
mtr->u_lock_register(savepoint);
root->page.lock.u_lock();
#ifdef BTR_CUR_HASH_ADAPT
if (root->index)
mtr_t::defer_drop_ahi(root, MTR_MEMO_PAGE_SX_FIX);
btr_search_drop_page_hash_index(root, true);
#endif
}
@@ -645,8 +644,7 @@ dberr_t btr_page_free(dict_index_t* index, buf_block_t* block, mtr_t* mtr,
mtr->u_lock_register(savepoint);
root->page.lock.u_lock();
#ifdef BTR_CUR_HASH_ADAPT
if (root->index)
mtr_t::defer_drop_ahi(root, MTR_MEMO_PAGE_SX_FIX);
btr_search_drop_page_hash_index(root, true);
#endif
}
err= fseg_free_page(&root->page.frame[blob ||

View File

@@ -278,10 +278,10 @@ latch_block:
latch_leaves->blocks[1] = block;
}
mtr->memo_push(block, MTR_MEMO_PAGE_X_FIX);
block->page.fix();
block->page.lock.x_lock();
mtr->memo_push(block, MTR_MEMO_PAGE_X_FIX);
#ifdef BTR_CUR_HASH_ADAPT
ut_ad(!btr_search_check_marked_free_index(block));
#endif
@@ -7017,10 +7017,11 @@ btr_store_big_rec_extern_fields(
mtr.start();
index->set_modified(mtr);
mtr.set_log_mode_sub(*btr_mtr);
mtr.memo_push(rec_block, MTR_MEMO_PAGE_X_FIX);
rec_block->page.fix();
rec_block->page.lock.x_lock();
mtr.memo_push(rec_block, MTR_MEMO_PAGE_X_FIX);
#ifdef BTR_CUR_HASH_ADAPT
ut_ad(!btr_search_check_marked_free_index(rec_block));
#endif
@@ -7396,9 +7397,10 @@ skip_free:
/* The buffer pool block containing the BLOB pointer is
exclusively latched by local_mtr. To satisfy some design
constraints, we must recursively latch it in mtr as well. */
mtr.memo_push(block, MTR_MEMO_PAGE_X_FIX);
block->fix();
block->page.lock.x_lock();
mtr.memo_push(block, MTR_MEMO_PAGE_X_FIX);
#ifdef BTR_CUR_HASH_ADAPT
ut_ad(!btr_search_check_marked_free_index(block));
#endif

View File

@@ -1292,10 +1292,6 @@ void btr_search_drop_page_hash_index(buf_block_t* block,
rec_offs* offsets;
retry:
/* This debug check uses a dirty read that could theoretically cause
false positives while buf_pool.clear_hash_index() is executing. */
assert_block_ahi_valid(block);
if (!block->index) {
return;
}

View File

@@ -2815,12 +2815,10 @@ get_latch:
goto page_id_mismatch;
}
get_latch_valid:
#ifdef BTR_CUR_HASH_ADAPT
if (block->index) {
mtr_t::defer_drop_ahi(block, fix_type);
}
#endif /* BTR_CUR_HASH_ADAPT */
mtr->memo_push(block, fix_type);
#ifdef BTR_CUR_HASH_ADAPT
btr_search_drop_page_hash_index(block, true);
#endif /* BTR_CUR_HASH_ADAPT */
break;
case RW_SX_LATCH:
fix_type = MTR_MEMO_PAGE_SX_FIX;

View File

@@ -1098,7 +1098,7 @@ dict_create_table_step(
}
if (node->state == TABLE_ADD_TO_CACHE) {
node->table->can_be_evicted = true;
node->table->can_be_evicted = !node->table->fts;
node->table->add_to_cache();
err = DB_SUCCESS;

View File

@@ -1665,7 +1665,7 @@ dict_table_rename_in_cache(
in UTF-8 charset. The variable fkid here is used
to store foreign key constraint name in charset
my_charset_filename for comparison further below. */
char fkid[MAX_TABLE_NAME_LEN+20];
char fkid[MAX_TABLE_NAME_LEN * 2 + 20];
/* The old table name in my_charset_filename is stored
in old_name_cs_filename */
@@ -1697,7 +1697,8 @@ dict_table_rename_in_cache(
}
}
strncpy(fkid, foreign->id, MAX_TABLE_NAME_LEN);
strncpy(fkid, foreign->id, (sizeof fkid) - 1);
fkid[(sizeof fkid) - 1] = '\0';
const bool on_tmp = dict_table_t::is_temporary_name(
fkid);
@@ -3522,10 +3523,11 @@ dict_table_get_highest_foreign_id(
for (dict_foreign_set::iterator it = table->foreign_set.begin();
it != table->foreign_set.end();
++it) {
char fkid[MAX_TABLE_NAME_LEN+20];
char fkid[MAX_TABLE_NAME_LEN * 2 + 20];
foreign = *it;
strcpy(fkid, foreign->id);
strncpy(fkid, foreign->id, (sizeof fkid) - 1);
fkid[(sizeof fkid) - 1] = '\0';
/* Convert foreign key identifier on dictionary memory
cache to filename charset. */
innobase_convert_to_filename_charset(

View File

@@ -245,7 +245,8 @@ void trx_t::commit(std::vector<pfs_os_file_t> &deleted)
ut_ad(ib_vector_is_empty(autoinc_locks));
mem_heap_empty(lock.lock_heap);
lock.table_locks.clear();
lock.was_chosen_as_deadlock_victim= false;
/* commit_persist() already reset this. */
ut_ad(!lock.was_chosen_as_deadlock_victim);
lock.n_rec_locks= 0;
while (dict_table_t *table= UT_LIST_GET_FIRST(lock.evicted_tables))
{

View File

@@ -14826,9 +14826,11 @@ ha_innobase::info_low(
stats.index_file_length
= ulonglong(stat_sum_of_other_index_sizes)
* size;
space->s_lock();
stats.delete_length = 1024
* fsp_get_available_space_in_free_extents(
*space);
space->s_unlock();
}
stats.check_time = 0;
stats.mrr_length_per_rec= (uint)ref_length + 8; // 8 = max(sizeof(void *));

View File

@@ -622,12 +622,6 @@ public:
PAGE_FLUSH_SYNC
};
#ifdef BTR_CUR_HASH_ADAPT
/** If a stale adaptive hash index exists on the block, drop it. */
ATTRIBUTE_COLD
static void defer_drop_ahi(buf_block_t *block, mtr_memo_type_t fix_type);
#endif
private:
/** Log a write of a byte string to a page.
@param block buffer page

View File

@@ -339,27 +339,11 @@ struct trx_lock_t
/** lock wait start time */
Atomic_relaxed<my_hrtime_t> suspend_time;
#if defined(UNIV_DEBUG) || !defined(DBUG_OFF)
/** 2=high priority WSREP thread has marked this trx to abort;
1=another transaction chose this as a victim in deadlock resolution. */
Atomic_relaxed<byte> was_chosen_as_deadlock_victim;
/** Clear the deadlock victim status. */
void clear_deadlock_victim()
{
#ifndef WITH_WSREP
was_chosen_as_deadlock_victim= false;
#elif defined __GNUC__ && (defined __i386__ || defined __x86_64__)
/* There is no 8-bit version of the 80386 BTR instruction.
Technically, this is the wrong addressing mode (16-bit), but
there are other data members stored after the byte. */
__asm__ __volatile__("lock btrw $0, %0"
: "+m" (was_chosen_as_deadlock_victim));
#else
was_chosen_as_deadlock_victim.fetch_and(byte(~1));
#endif
}
#ifdef WITH_WSREP
/** Flag the lock owner as a victim in Galera conflict resolution. */
void set_wsrep_victim()
{
@@ -373,7 +357,17 @@ struct trx_lock_t
was_chosen_as_deadlock_victim.fetch_or(2);
# endif
}
#endif
#else /* defined(UNIV_DEBUG) || !defined(DBUG_OFF) */
/** High priority WSREP thread has marked this trx to abort or
another transaction chose this as a victim in deadlock resolution. */
Atomic_relaxed<bool> was_chosen_as_deadlock_victim;
/** Flag the lock owner as a victim in Galera conflict resolution. */
void set_wsrep_victim() {
was_chosen_as_deadlock_victim= true;
}
#endif /* defined(UNIV_DEBUG) || !defined(DBUG_OFF) */
/** Next available rec_pool[] entry */
byte rec_cached;

View File

@@ -44,6 +44,7 @@ Created 5/7/1996 Heikki Tuuri
#include "row0vers.h"
#include "pars0pars.h"
#include "srv0mon.h"
#include "scope.h"
#include <set>
@@ -1275,6 +1276,14 @@ lock_rec_enqueue_waiting(
trx_t* trx = thr_get_trx(thr);
ut_ad(xtest() || trx->mutex_is_owner());
ut_ad(!trx->dict_operation_lock_mode);
/* Apart from Galera, only transactions that have waiting lock can be
chosen as deadlock victim. Only one lock can be waited for at a time,
and a transaction is associated with a single thread. That is why there
must not be waiting lock requests if the transaction is deadlock victim
and it is not WSREP. Galera transaction abort can be invoked from MDL
acquisition code when the transaction does not have waiting record
lock, that's why we check only deadlock victim bit here. */
ut_ad(!(trx->lock.was_chosen_as_deadlock_victim & 1));
if (trx->mysql_thd && thd_lock_wait_timeout(trx->mysql_thd) == 0) {
trx->error_state = DB_LOCK_WAIT_TIMEOUT;
@@ -1292,7 +1301,6 @@ lock_rec_enqueue_waiting(
}
trx->lock.wait_thr = thr;
trx->lock.clear_deadlock_victim();
DBUG_LOG("ib_lock", "trx " << ib::hex(trx->id)
<< " waits for lock in index " << index->name
@@ -1475,7 +1483,14 @@ lock_rec_lock(
que_thr_t* thr) /*!< in: query thread */
{
trx_t *trx= thr_get_trx(thr);
/* There must not be lock requests for reads or updates if transaction was
chosen as deadlock victim. Apart from Galera, only transactions that have
waiting lock may be chosen as deadlock victims. Only one lock can be waited
for at a time, and a transaction is associated with a single thread. Galera
transaction abort can be invoked from MDL acquisition code when the
transaction does not have waiting lock, that's why we check only deadlock
victim bit here. */
ut_ad(!(trx->lock.was_chosen_as_deadlock_victim & 1));
ut_ad(!srv_read_only_mode);
ut_ad(((LOCK_MODE_MASK | LOCK_TABLE) & mode) == LOCK_S ||
((LOCK_MODE_MASK | LOCK_TABLE) & mode) == LOCK_X);
@@ -1627,7 +1642,9 @@ void lock_sys_t::wait_resume(THD *thd, my_hrtime_t start, my_hrtime_t now)
#ifdef HAVE_REPLICATION
ATTRIBUTE_NOINLINE MY_ATTRIBUTE((nonnull))
/** Report lock waits to parallel replication.
/** Report lock waits to parallel replication. Sets
trx->error_state= DB_DEADLOCK if trx->lock.was_chosen_as_deadlock_victim was
set when lock_sys.wait_mutex was unlocked.
@param trx transaction that may be waiting for a lock
@param wait_lock lock that is being waited for */
static void lock_wait_rpl_report(trx_t *trx)
@@ -1642,7 +1659,8 @@ static void lock_wait_rpl_report(trx_t *trx)
ut_ad(!(wait_lock->type_mode & LOCK_AUTO_INC));
/* This would likely be too large to attempt to use a memory transaction,
even for wait_lock->is_table(). */
if (!lock_sys.wr_lock_try())
const bool nowait= lock_sys.wr_lock_try();
if (!nowait)
{
mysql_mutex_unlock(&lock_sys.wait_mutex);
lock_sys.wr_lock(SRW_LOCK_CALL);
@@ -1652,6 +1670,10 @@ static void lock_wait_rpl_report(trx_t *trx)
{
func_exit:
lock_sys.wr_unlock();
/* trx->lock.was_chosen_as_deadlock_victim can be set when
lock_sys.wait_mutex was unlocked, let's check it. */
if (!nowait && trx->lock.was_chosen_as_deadlock_victim)
trx->error_state= DB_DEADLOCK;
return;
}
ut_ad(wait_lock->is_waiting());
@@ -1700,7 +1722,13 @@ dberr_t lock_wait(que_thr_t *thr)
trx_t *trx= thr_get_trx(thr);
if (trx->mysql_thd)
DEBUG_SYNC_C("lock_wait_suspend_thread_enter");
DEBUG_SYNC_C("lock_wait_start");
/* Create the sync point for any quit from the function. */
ut_d(SCOPE_EXIT([trx]() {
if (trx->mysql_thd)
DEBUG_SYNC_C("lock_wait_end");
}));
/* InnoDB system transactions may use the global value of
innodb_lock_wait_timeout, because trx->mysql_thd == NULL. */
@@ -1731,11 +1759,8 @@ dberr_t lock_wait(que_thr_t *thr)
{
/* The lock has already been released or this transaction
was chosen as a deadlock victim: no need to wait */
if (trx->lock.was_chosen_as_deadlock_victim.fetch_and(byte(~1)))
trx->error_state= DB_DEADLOCK;
else
trx->error_state= DB_SUCCESS;
trx->error_state=
trx->lock.was_chosen_as_deadlock_victim ? DB_DEADLOCK : DB_SUCCESS;
return trx->error_state;
}
@@ -1770,7 +1795,7 @@ dberr_t lock_wait(que_thr_t *thr)
wait_lock->un_member.tab_lock.table->id <= DICT_FIELDS_ID);
thd_wait_begin(trx->mysql_thd, (type_mode & LOCK_TABLE)
? THD_WAIT_TABLE_LOCK : THD_WAIT_ROW_LOCK);
dberr_t error_state= DB_SUCCESS;
trx->error_state= DB_SUCCESS;
mysql_mutex_lock(&lock_sys.wait_mutex);
if (trx->lock.wait_lock)
@@ -1778,23 +1803,28 @@ dberr_t lock_wait(que_thr_t *thr)
if (Deadlock::check_and_resolve(trx))
{
ut_ad(!trx->lock.wait_lock);
error_state= DB_DEADLOCK;
trx->error_state= DB_DEADLOCK;
goto end_wait;
}
}
else
{
/* trx->lock.was_chosen_as_deadlock_victim can be changed before
lock_sys.wait_mutex is acquired, so let's check it once more. */
trx->error_state=
trx->lock.was_chosen_as_deadlock_victim ? DB_DEADLOCK : DB_SUCCESS;
goto end_wait;
}
if (row_lock_wait)
lock_sys.wait_start();
trx->error_state= DB_SUCCESS;
#ifdef HAVE_REPLICATION
if (rpl)
lock_wait_rpl_report(trx);
#endif
trx->error_state= DB_SUCCESS;
while (trx->lock.wait_lock)
{
int err;
@@ -1807,20 +1837,19 @@ dberr_t lock_wait(que_thr_t *thr)
else
err= my_cond_timedwait(&trx->lock.cond, &lock_sys.wait_mutex.m_mutex,
&abstime);
error_state= trx->error_state;
switch (error_state) {
switch (trx->error_state) {
case DB_DEADLOCK:
case DB_INTERRUPTED:
break;
default:
ut_ad(error_state != DB_LOCK_WAIT_TIMEOUT);
ut_ad(trx->error_state != DB_LOCK_WAIT_TIMEOUT);
/* Dictionary transactions must ignore KILL, because they could
be executed as part of a multi-transaction DDL operation,
such as rollback_inplace_alter_table() or ha_innobase::delete_table(). */
if (!trx->dict_operation && trx_is_interrupted(trx))
/* innobase_kill_query() can only set trx->error_state=DB_INTERRUPTED
for any transaction that is attached to a connection. */
error_state= DB_INTERRUPTED;
trx->error_state= DB_INTERRUPTED;
else if (!err)
continue;
#ifdef WITH_WSREP
@@ -1828,7 +1857,7 @@ dberr_t lock_wait(que_thr_t *thr)
#endif
else
{
error_state= DB_LOCK_WAIT_TIMEOUT;
trx->error_state= DB_LOCK_WAIT_TIMEOUT;
lock_sys.timeouts++;
}
}
@@ -1848,8 +1877,7 @@ end_wait:
mysql_mutex_unlock(&lock_sys.wait_mutex);
thd_wait_end(trx->mysql_thd);
trx->error_state= error_state;
return error_state;
return trx->error_state;
}
@@ -1862,7 +1890,7 @@ static void lock_wait_end(trx_t *trx)
ut_ad(state == TRX_STATE_ACTIVE || state == TRX_STATE_PREPARED);
ut_ad(trx->lock.wait_thr);
if (trx->lock.was_chosen_as_deadlock_victim.fetch_and(byte(~1)))
if (trx->lock.was_chosen_as_deadlock_victim)
{
ut_ad(state == TRX_STATE_ACTIVE);
trx->error_state= DB_DEADLOCK;
@@ -3401,17 +3429,18 @@ lock_table_enqueue_waiting(
ut_ad(trx->mutex_is_owner());
ut_ad(!trx->dict_operation_lock_mode);
#ifdef WITH_WSREP
if (trx->is_wsrep() && trx->lock.was_chosen_as_deadlock_victim) {
return(DB_DEADLOCK);
}
#endif /* WITH_WSREP */
/* Enqueue the lock request that will wait to be granted */
lock_table_create(table, mode | LOCK_WAIT, trx, c_lock);
trx->lock.wait_thr = thr;
trx->lock.clear_deadlock_victim();
/* Apart from Galera, only transactions that have waiting lock
may be chosen as deadlock victims. Only one lock can be waited for at a
time, and a transaction is associated with a single thread. That is why
there must not be waiting lock requests if the transaction is deadlock
victim and it is not WSREP. Galera transaction abort can be invoked
from MDL acquisition code when the transaction does not have waiting
lock, that's why we check only deadlock victim bit here. */
ut_ad(!(trx->lock.was_chosen_as_deadlock_victim & 1));
MONITOR_INC(MONITOR_TABLELOCK_WAIT);
return(DB_LOCK_WAIT);
@@ -3949,7 +3978,6 @@ released:
mysql_mutex_unlock(&lock_sys.wait_mutex);
}
trx->lock.was_chosen_as_deadlock_victim= false;
trx->lock.n_rec_locks= 0;
#ifdef UNIV_DEBUG
@@ -5718,10 +5746,12 @@ dberr_t lock_sys_t::cancel(trx_t *trx, lock_t *lock)
lock_sys.rd_lock(SRW_LOCK_CALL);
mysql_mutex_lock(&lock_sys.wait_mutex);
lock= trx->lock.wait_lock;
if (!lock);
else if (check_victim && trx->lock.was_chosen_as_deadlock_victim)
/* Even if waiting lock was cancelled while lock_sys.wait_mutex was
unlocked, we need to return deadlock error if transaction was chosen
as deadlock victim to rollback it */
if (check_victim && trx->lock.was_chosen_as_deadlock_victim)
err= DB_DEADLOCK;
else
else if (lock)
goto resolve_table_lock;
}
else
@@ -5769,10 +5799,12 @@ retreat:
lock_sys.wr_lock(SRW_LOCK_CALL);
mysql_mutex_lock(&lock_sys.wait_mutex);
lock= trx->lock.wait_lock;
if (!lock);
else if (check_victim && trx->lock.was_chosen_as_deadlock_victim)
/* Even if waiting lock was cancelled while lock_sys.wait_mutex was
unlocked, we need to return deadlock error if transaction was chosen
as deadlock victim to rollback it */
if (check_victim && trx->lock.was_chosen_as_deadlock_victim)
err= DB_DEADLOCK;
else
else if (lock)
goto resolve_record_lock;
}
else
@@ -5850,6 +5882,7 @@ while holding a clustered index leaf page latch.
lock request was released */
dberr_t lock_trx_handle_wait(trx_t *trx)
{
DEBUG_SYNC_C("lock_trx_handle_wait_enter");
if (trx->lock.was_chosen_as_deadlock_victim)
return DB_DEADLOCK;
if (!trx->lock.wait_lock)

View File

@@ -1287,43 +1287,6 @@ bool mtr_t::memo_contains(const fil_space_t& space, bool shared)
return true;
}
#ifdef BTR_CUR_HASH_ADAPT
/** If a stale adaptive hash index exists on the block, drop it. */
ATTRIBUTE_COLD
void mtr_t::defer_drop_ahi(buf_block_t *block, mtr_memo_type_t fix_type)
{
switch (fix_type) {
default:
ut_ad(fix_type == MTR_MEMO_BUF_FIX);
/* We do not drop the adaptive hash index, because safely doing so
would require acquiring exclusive block->page.lock, which could
lead to hangs in some access paths. Those code paths should have
no business accessing the adaptive hash index anyway. */
break;
case MTR_MEMO_PAGE_S_FIX:
/* Temporarily release our S-latch. */
block->page.lock.s_unlock();
block->page.lock.x_lock();
if (dict_index_t *index= block->index)
if (index->freed())
btr_search_drop_page_hash_index(block);
block->page.lock.x_unlock();
block->page.lock.s_lock();
ut_ad(!block->page.is_read_fixed());
break;
case MTR_MEMO_PAGE_SX_FIX:
block->page.lock.u_x_upgrade();
if (dict_index_t *index= block->index)
if (index->freed())
btr_search_drop_page_hash_index(block);
block->page.lock.x_u_downgrade();
break;
case MTR_MEMO_PAGE_X_FIX:
btr_search_drop_page_hash_index(block);
}
}
#endif /* BTR_CUR_HASH_ADAPT */
/** Upgrade U-latched pages to X */
struct UpgradeX
{
@@ -1378,8 +1341,7 @@ void mtr_t::page_lock(buf_block_t *block, ulint rw_latch)
ut_d(const auto state= block->page.state());
ut_ad(state > buf_page_t::FREED);
ut_ad(state > buf_page_t::WRITE_FIX || state < buf_page_t::READ_FIX);
switch (rw_latch)
{
switch (rw_latch) {
case RW_NO_LATCH:
fix_type= MTR_MEMO_BUF_FIX;
goto done;
@@ -1405,10 +1367,8 @@ void mtr_t::page_lock(buf_block_t *block, ulint rw_latch)
}
#ifdef BTR_CUR_HASH_ADAPT
if (dict_index_t *index= block->index)
if (index->freed())
defer_drop_ahi(block, fix_type);
#endif /* BTR_CUR_HASH_ADAPT */
btr_search_drop_page_hash_index(block, true);
#endif
done:
ut_ad(state < buf_page_t::UNFIXED ||
@@ -1638,8 +1598,10 @@ void mtr_t::free(const fil_space_t &space, uint32_t offset)
if (is_logged())
{
m_memo.for_each_block_in_reverse
(CIterate<MarkFreed>((MarkFreed{{space.id, offset}})));
CIterate<MarkFreed> mf{MarkFreed{{space.id, offset}}};
m_memo.for_each_block_in_reverse(mf);
if (mf.functor.freed && !m_made_dirty)
m_made_dirty= is_block_dirtied(mf.functor.freed);
m_log.close(log_write<FREE_PAGE>({space.id, offset}, nullptr));
}
}

View File

@@ -118,7 +118,7 @@ public:
size_t pending_io_count()
{
return (size_t)m_max_aio - m_cache.size();
return m_cache.pos();
}
tpool::task_group* get_task_group()

View File

@@ -399,11 +399,11 @@ static dberr_t trx_purge_free_segment(trx_rseg_t *rseg, fil_addr_t hdr_addr)
mtr.commit();
mtr.start();
mtr.flag_modified();
mtr.memo_push(rseg_hdr, MTR_MEMO_PAGE_X_FIX);
mtr.memo_push(block, MTR_MEMO_PAGE_X_MODIFY);
rseg->latch.wr_lock(SRW_LOCK_CALL);
rseg_hdr->page.lock.x_lock();
block->page.lock.x_lock();
mtr.memo_push(rseg_hdr, MTR_MEMO_PAGE_X_FIX);
mtr.memo_push(block, MTR_MEMO_PAGE_X_MODIFY);
}
/* The page list may now be inconsistent, but the length field

View File

@@ -1859,9 +1859,9 @@ trx_undo_page_report_rename(trx_t* trx, const dict_table_t* table,
byte* const start = block->page.frame + first_free;
size_t len = strlen(table->name.m_name);
const size_t fixed = 2 + 1 + 11 + 11 + 2;
ut_ad(len <= NAME_LEN * 2 + 1);
ut_ad(len <= NAME_CHAR_LEN * 5 * 2 + 1);
/* The -10 is used in trx_undo_left() */
compile_time_assert((NAME_LEN * 1) * 2 + fixed
compile_time_assert(NAME_CHAR_LEN * 5 * 2 + fixed
+ TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_HDR_SIZE
< UNIV_PAGE_SIZE_MIN - 10 - FIL_PAGE_DATA_END);

View File

@@ -135,6 +135,9 @@ inline void trx_t::rollback_low(trx_savept_t *savept)
}
else
{
/* There must not be partial rollback if transaction was chosen as deadlock
victim. Galera transaction abort can be invoked during partial rollback. */
ut_ad(!(lock.was_chosen_as_deadlock_victim & 1));
ut_a(error_state == DB_SUCCESS);
const undo_no_t limit= savept->least_undo_no;
apply_online_log= false;
@@ -211,6 +214,10 @@ dberr_t trx_rollback_for_mysql(trx_t* trx)
case TRX_STATE_NOT_STARTED:
trx->will_lock = false;
ut_ad(trx->mysql_thd);
/* Galera transaction abort can be invoked from MDL acquision
code, so trx->lock.was_chosen_as_deadlock_victim can be set
even if trx->state is TRX_STATE_NOT_STARTED. */
ut_ad(!(trx->lock.was_chosen_as_deadlock_victim & 1));
#ifdef WITH_WSREP
trx->wsrep= false;
trx->lock.was_chosen_as_deadlock_victim= false;
@@ -418,9 +425,6 @@ trx_rollback_to_savepoint_for_mysql_low(
trx_mark_sql_stat_end(trx);
trx->op_info = "";
#ifdef WITH_WSREP
trx->lock.was_chosen_as_deadlock_victim = false;
#endif
return(err);
}

View File

@@ -1379,9 +1379,8 @@ TRANSACTIONAL_INLINE inline void trx_t::commit_in_memory(const mtr_t *mtr)
wsrep= false;
wsrep_commit_ordered(mysql_thd);
}
ut_ad(!(lock.was_chosen_as_deadlock_victim & byte(~2U)));
lock.was_chosen_as_deadlock_victim= false;
#endif /* WITH_WSREP */
lock.was_chosen_as_deadlock_victim= false;
}
void trx_t::commit_cleanup()

View File

@@ -23,13 +23,13 @@
solution was needed than the one-to-one conversion table. To
note a few, here is an example of a Czech sorting sequence:
co < hlaska < hláska < hlava < chlapec < krtek
co < hlaska < hláska < hlava < chlapec < krtek
It because some of the rules are: double char 'ch' is sorted
between 'h' and 'i'. Accented character 'á' (a with acute) is
between 'h' and 'i'. Accented character 'á' (a with acute) is
sorted after 'a' and before 'b', but only if the word is
otherwise the same. However, because 's' is sorted before 'v'
in hlava, the accentness of 'á' is overridden. There are many
in hlava, the accentness of 'á' is overridden. There are many
more rules.
This file defines functions my_strxfrm and my_strcoll for
@@ -42,8 +42,9 @@
passes, that's why we need four times more space for expanded
string.
This file also contains the ISO-Latin-2 definitions of
characters.
The non-ASCII literal strings in this file are encoded
in the iso-8859-2 / latin-2 character set
(https://en.wikipedia.org/wiki/ISO/IEC_8859-2)
Author: (c) 1997--1998 Jan Pazdziora, adelton@fi.muni.cz
Jan Pazdziora has a shared copyright for this code
@@ -112,7 +113,7 @@ static const struct wordvalue doubles[] = {
};
/*
Unformal description of the algorithm:
Informal description of the algorithm:
We walk the string left to right.
@@ -127,7 +128,7 @@ static const struct wordvalue doubles[] = {
End of pass is marked with value 1 on the output.
For each character, we read it's value from the table.
For each character, we read its value from the table.
If the value is ignore (0), we go straight to the next character.
@@ -139,31 +140,6 @@ static const struct wordvalue doubles[] = {
exists behind it, find its value.
We append 0 to the end.
---
Neformální popis algoritmu:
Procházíme řetězec zleva doprava.
Konec řetězce je předán buď jako parametr, nebo je to *p == 0.
Toto je ošetřeno makrem IS_END.
Pokud jsme došli na konec řetězce při průchodu 0, nejdeme na
začátek, ale na uloženou pozici, protože první a druhý průchod
běží současně.
Konec vstupu (průchodu) označíme na výstupu hodnotou 1.
Pro každý znak řetězce načteme hodnotu z třídící tabulky.
Jde-li o hodnotu ignorovat (0), skočíme ihned na další znak..
Jde-li o hodnotu konec slova (2) a je to průchod 0 nebo 1,
přeskočíme všechny další 0 -- 2 a prohodíme průchody.
Jde-li o kompozitní znak (255), otestujeme, zda následuje
správný do dvojice, dohledáme správnou hodnotu.
Na konci připojíme znak 0
*/
#define ADD_TO_RESULT(dest, len, totlen, value) \
@@ -336,24 +312,23 @@ my_strnxfrm_czech(CHARSET_INFO *cs __attribute__((unused)),
/*
Neformální popis algoritmu:
Informal description of the algorithm:
procházíme řetězec zleva doprava
konec řetězce poznáme podle *p == 0
pokud jsme došli na konec řetězce při průchodu 0, nejdeme na
začátek, ale na uloženou pozici, protože první a druhý
průchod běží současně
konec vstupu (průchodu) označíme na výstupu hodnotou 1
we pass the chain from left to right
we know the end of the string by *p == 0
if we reached the end of the string on transition 0, then we don't go to
start, but to the saved position, because the first and second
the passage runs concurrently
we mark the end of the input (transition) with the value 1 on the output
načteme hodnotu z třídící tabulky
jde-li o hodnotu ignorovat (0), skočíme na další průchod
jde-li o hodnotu konec slova (2) a je to průchod 0 nebo 1,
přeskočíme všechny další 0 -- 2 a prohodíme
průchody
jde-li o kompozitní znak (255), otestujeme, zda následuje
správný do dvojice, dohledáme správnou hodnotu
then we load the value from the sorting table
if the value is ignore (0), we jump to the next pass
if the value is the end of the word (2) and it is a 0 or 1 transition,
we skip all the other 0 -- 2 and switch transitions
if it is a composite character (255), we test whether it follows
correct to the pair, we find the correct value
na konci připojíme znak 0
then we add the character 0 at the end
*/

View File

@@ -504,19 +504,19 @@ struct charset_info_st my_charset_latin1_nopad=
*
* The modern sort order is used, where:
*
* 'ä' -> "ae"
* 'ö' -> "oe"
* 'ü' -> "ue"
* 'ß' -> "ss"
* 'ä' -> "ae"
* 'ö' -> "oe"
* 'ü' -> "ue"
* 'ß' -> "ss"
*/
/*
* This is a simple latin1 mapping table, which maps all accented
* characters to their non-accented equivalents. Note: in this
* table, 'ä' is mapped to 'A', 'ÿ' is mapped to 'Y', etc. - all
* table, 'ä' is mapped to 'A', 'ÿ' is mapped to 'Y', etc. - all
* accented characters except the following are treated the same way.
* Ü, ü, Ö, ö, Ä, ä
* Ü, ü, Ö, ö, Ä, ä
*/
static const uchar sort_order_latin1_de[] = {
@@ -582,7 +582,7 @@ static const uchar combo2map[]={
my_strnxfrm_latin_de() on both strings and compared the result strings.
This means that:
Ä must also matches ÁE and , because my_strxn_frm_latin_de() will convert
Ä must also matches ÁE and , because my_strxn_frm_latin_de() will convert
both to AE.
The other option would be to not do any accent removal in
@@ -708,7 +708,7 @@ void my_hash_sort_latin1_de(CHARSET_INFO *cs __attribute__((unused)),
/*
Remove end space. We have to do this to be able to compare
'AE' and 'Ä' as identical
'AE' and 'Ä' as identical
*/
end= skip_trailing_space(key, len);

View File

@@ -40,79 +40,121 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111 - 1301 USA*/
namespace tpool
{
enum cache_notification_mode
{
NOTIFY_ONE,
NOTIFY_ALL
};
/**
Generic "pointer" cache of a fixed size
with fast put/get operations.
Compared to STL containers, is faster/does not
do allocations. However, put() operation will wait
if there is no free items.
Compared to STL containers,e.g stack or queue
is faster/does not do allocations.
However, get() operation will wait if there is no free items.
We assume that put() will only put back the elements that
were retrieved previously with get().
*/
template<typename T> class cache
{
/** Protects updates of m_pos and m_cache members */
std::mutex m_mtx;
/**
Notify waiting threads about "cache full" or "cache not empty" conditions
@see get() and wait()
*/
std::condition_variable m_cv;
std::vector<T> m_base;
/** Cached items vector.Does not change after construction */
std::vector<T> m_base;
/**
Pointers to cached items. Protected by m_mtx. Does not grow after
construction. Elements in position [0,m_pos-1] are "borrowed",
elements in position [m_pos,capacity()-1] are "free"
*/
std::vector<T*> m_cache;
cache_notification_mode m_notification_mode;
/** Number of threads waiting for "cache full" condition (s. wait())
Protected by m_mtx */
int m_waiters;
/** Current cache size. Protected by m_mtx*/
size_t m_pos;
private:
inline size_t capacity()
{
return m_base.size();
}
/**
@return true if cache is full (no items are borrowed)
*/
bool is_full()
{
return m_cache.size() == m_base.size();
return m_pos == 0;
}
/**
@return true if cache is empty (all items are borrowed)
*/
bool is_empty()
{
return m_pos == capacity();
}
public:
cache(size_t count, cache_notification_mode mode= tpool::cache_notification_mode::NOTIFY_ALL):
m_mtx(), m_cv(), m_base(count),m_cache(count), m_notification_mode(mode),m_waiters()
/**
Constructor
@param size - maximum number of items in cache
*/
cache(size_t size) : m_mtx(), m_cv(), m_base(size), m_cache(size),
m_waiters(), m_pos(0)
{
for(size_t i = 0 ; i < count; i++)
m_cache[i]=&m_base[i];
for(size_t i= 0 ; i < size; i++)
m_cache[i]= &m_base[i];
}
T* get(bool blocking=true)
/**
Retrieve an item from cache. Waits for free item, if cache is
currently empty.
@return borrowed item
*/
T* get()
{
std::unique_lock<std::mutex> lk(m_mtx);
if (blocking)
{
while(m_cache.empty())
m_cv.wait(lk);
}
else
{
if(m_cache.empty())
return nullptr;
}
T* ret = m_cache.back();
m_cache.pop_back();
return ret;
while(is_empty())
m_cv.wait(lk);
assert(m_pos < capacity());
// return last element
return m_cache[m_pos++];
}
/**
Put back an item to cache.
@param item - item to put back
*/
void put(T *ele)
{
std::unique_lock<std::mutex> lk(m_mtx);
m_cache.push_back(ele);
if (m_notification_mode == NOTIFY_ONE)
m_cv.notify_one();
else if(m_cache.size() == 1)
m_cv.notify_all(); // Signal cache is not empty
else if(m_waiters && is_full())
m_cv.notify_all(); // Signal cache is full
assert(!is_full());
// put element to the logical end of the array
m_cache[--m_pos] = ele;
/* Notify waiters when the cache becomes
not empty, or when it becomes full */
if (m_pos == 1 || (m_waiters && is_full()))
m_cv.notify_all();
}
/** Check if pointer represents cached element */
bool contains(T* ele)
{
return ele >= &m_base[0] && ele <= &m_base[m_base.size() -1];
// No locking required, m_base does not change after construction.
return ele >= &m_base[0] && ele <= &m_base[capacity() - 1];
}
/* Wait until cache is full.*/
/** Wait until cache is full.*/
void wait()
{
std::unique_lock<std::mutex> lk(m_mtx);
@@ -122,9 +164,13 @@ public:
m_waiters--;
}
TPOOL_SUPPRESS_TSAN size_t size()
/**
@return approximate number of "borrowed" items.
A "dirty" read, not used in any critical functionality.
*/
TPOOL_SUPPRESS_TSAN size_t pos()
{
return m_cache.size();
return m_pos;
}
};