Merge remote-tracking branch 'origin/10.3' into 10.4
This commit is contained in:
commit
9c0f5a252b
@ -47,7 +47,7 @@ IF(CMAKE_C_COMPILER MATCHES "icl")
|
||||
ENDIF()
|
||||
|
||||
ADD_DEFINITIONS(-D_WINDOWS -D__WIN__ -D_CRT_SECURE_NO_DEPRECATE)
|
||||
ADD_DEFINITIONS(-D_WIN32_WINNT=0x0600)
|
||||
ADD_DEFINITIONS(-D_WIN32_WINNT=0x0A00)
|
||||
# We do not want the windows.h macros min/max
|
||||
ADD_DEFINITIONS(-DNOMINMAX)
|
||||
# Speed up build process excluding unused header files
|
||||
|
@ -10,9 +10,9 @@ t1 CREATE TABLE `t1` (
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=latin1
|
||||
insert into t1 values (100,100);
|
||||
insert into t1 values (1,1);
|
||||
ERROR 23000: CONSTRAINT `a` failed for `test`.`t1`
|
||||
ERROR 23000: CONSTRAINT `t1.a` failed for `test`.`t1`
|
||||
insert into t1 values (20,1);
|
||||
ERROR 23000: CONSTRAINT `b` failed for `test`.`t1`
|
||||
ERROR 23000: CONSTRAINT `t1.b` failed for `test`.`t1`
|
||||
insert into t1 values (20,30);
|
||||
ERROR 23000: CONSTRAINT `min` failed for `test`.`t1`
|
||||
insert into t1 values (500,500);
|
||||
@ -60,7 +60,7 @@ t1 CREATE TABLE `t1` (
|
||||
CONSTRAINT `CONSTRAINT_1` CHECK (`a` + `b` + `c` < 500)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=latin1
|
||||
insert into t1 values(105,105,105);
|
||||
ERROR 23000: CONSTRAINT `c` failed for `test`.`t1`
|
||||
ERROR 23000: CONSTRAINT `t1.c` failed for `test`.`t1`
|
||||
insert into t1 values(249,249,9);
|
||||
ERROR 23000: CONSTRAINT `CONSTRAINT_1` failed for `test`.`t1`
|
||||
insert into t1 values(105,105,9);
|
||||
@ -145,7 +145,7 @@ ERROR HY000: Function or expression '@b' cannot be used in the CHECK clause of `
|
||||
create table t1 (a int check (a = 1));
|
||||
insert t1 values (1);
|
||||
insert t1 values (2);
|
||||
ERROR 23000: CONSTRAINT `a` failed for `test`.`t1`
|
||||
ERROR 23000: CONSTRAINT `t1.a` failed for `test`.`t1`
|
||||
insert t1 values (NULL);
|
||||
select * from t1;
|
||||
a
|
||||
@ -165,13 +165,13 @@ ERROR 22007: Truncated incorrect DOUBLE value: 'Ken'
|
||||
SHOW WARNINGS;
|
||||
Level Code Message
|
||||
Error 1292 Truncated incorrect DOUBLE value: 'Ken'
|
||||
Error 4025 CONSTRAINT `FirstName` failed for `test`.`t1`
|
||||
Error 4025 CONSTRAINT `t1.FirstName` failed for `test`.`t1`
|
||||
INSERT INTO t1 VALUES (NULL, 'Ken'),(NULL, 'Brian');
|
||||
ERROR 22007: Truncated incorrect DOUBLE value: 'Ken'
|
||||
SHOW WARNINGS;
|
||||
Level Code Message
|
||||
Error 1292 Truncated incorrect DOUBLE value: 'Ken'
|
||||
Error 4025 CONSTRAINT `FirstName` failed for `test`.`t1`
|
||||
Error 4025 CONSTRAINT `t1.FirstName` failed for `test`.`t1`
|
||||
INSERT IGNORE INTO t1 VALUES (NULL, 'Ken');
|
||||
Warnings:
|
||||
Warning 1292 Truncated incorrect DOUBLE value: 'Ken'
|
||||
@ -197,3 +197,28 @@ EmployeeID FirstName
|
||||
5 Ken
|
||||
6 Brian
|
||||
drop table t1;
|
||||
#
|
||||
# MDEV-16630: Ambiguous error message when check constraint
|
||||
# matches table name
|
||||
#
|
||||
use test;
|
||||
drop table if exists t;
|
||||
create table t(a int, b int check(b>0),
|
||||
constraint b check(a<b), constraint a check(a>0),
|
||||
constraint x check (a>10));
|
||||
show create table t;
|
||||
Table Create Table
|
||||
t CREATE TABLE `t` (
|
||||
`a` int(11) DEFAULT NULL,
|
||||
`b` int(11) DEFAULT NULL CHECK (`b` > 0),
|
||||
CONSTRAINT `b` CHECK (`a` < `b`),
|
||||
CONSTRAINT `a` CHECK (`a` > 0),
|
||||
CONSTRAINT `x` CHECK (`a` > 10)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=latin1
|
||||
# Field constraint 'b' will fail
|
||||
insert into t values (-1, 0);
|
||||
ERROR 23000: CONSTRAINT `t.b` failed for `test`.`t`
|
||||
# Table constraint 'b' will fail
|
||||
insert into t values (1,1);
|
||||
ERROR 23000: CONSTRAINT `b` failed for `test`.`t`
|
||||
drop table t;
|
||||
|
@ -135,3 +135,31 @@ INSERT INTO t1 VALUES (NULL, 'Ken'),(NULL, 'Brian');
|
||||
set sql_mode=default;
|
||||
select * from t1;
|
||||
drop table t1;
|
||||
|
||||
--echo #
|
||||
--echo # MDEV-16630: Ambiguous error message when check constraint
|
||||
--echo # matches table name
|
||||
--echo #
|
||||
|
||||
use test;
|
||||
--disable_warnings
|
||||
drop table if exists t;
|
||||
--enable_warnings
|
||||
|
||||
create table t(a int, b int check(b>0),
|
||||
constraint b check(a<b), constraint a check(a>0),
|
||||
constraint x check (a>10));
|
||||
|
||||
show create table t;
|
||||
|
||||
# Generate error when field constraint 'b' is violated
|
||||
--echo # Field constraint 'b' will fail
|
||||
--error ER_CONSTRAINT_FAILED
|
||||
insert into t values (-1, 0);
|
||||
|
||||
# Generate error when table constraint 'b' is violated.
|
||||
--echo # Table constraint 'b' will fail
|
||||
--error ER_CONSTRAINT_FAILED
|
||||
insert into t values (1,1);
|
||||
|
||||
drop table t;
|
||||
|
@ -1472,3 +1472,17 @@ SELECT LEFT(a, 10), LENGTH(a) FROM t1;
|
||||
LEFT(a, 10) LENGTH(a)
|
||||
aaaaaaaaaa 255
|
||||
DROP TABLE t1;
|
||||
#
|
||||
# MDEV-16729 VARCHAR COMPRESSED is created with a wrong length for multi-byte character sets
|
||||
#
|
||||
CREATE OR REPLACE TABLE t1 (a VARCHAR(1000) CHARACTER SET utf8 COMPRESSED);
|
||||
SHOW CREATE TABLE t1;
|
||||
Table Create Table
|
||||
t1 CREATE TABLE `t1` (
|
||||
`a` varchar(1000) /*!100301 COMPRESSED*/ CHARACTER SET utf8 DEFAULT NULL
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=latin1
|
||||
SELECT COLUMN_TYPE FROM INFORMATION_SCHEMA.COLUMNS
|
||||
WHERE TABLE_SCHEMA='test' AND TABLE_NAME='t1';
|
||||
COLUMN_TYPE
|
||||
varchar(1000) /*!100301 COMPRESSED*/
|
||||
DROP TABLE t1;
|
||||
|
@ -170,3 +170,14 @@ CREATE TABLE t1(a TINYTEXT COMPRESSED);
|
||||
INSERT INTO t1 VALUES(REPEAT('a', 255));
|
||||
SELECT LEFT(a, 10), LENGTH(a) FROM t1;
|
||||
DROP TABLE t1;
|
||||
|
||||
|
||||
--echo #
|
||||
--echo # MDEV-16729 VARCHAR COMPRESSED is created with a wrong length for multi-byte character sets
|
||||
--echo #
|
||||
|
||||
CREATE OR REPLACE TABLE t1 (a VARCHAR(1000) CHARACTER SET utf8 COMPRESSED);
|
||||
SHOW CREATE TABLE t1;
|
||||
SELECT COLUMN_TYPE FROM INFORMATION_SCHEMA.COLUMNS
|
||||
WHERE TABLE_SCHEMA='test' AND TABLE_NAME='t1';
|
||||
DROP TABLE t1;
|
||||
|
@ -7,7 +7,7 @@ t1 CREATE TABLE `t1` (
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=latin1
|
||||
insert into t1 values (1);
|
||||
insert into t1 values (0);
|
||||
ERROR 23000: CONSTRAINT `a` failed for `test`.`t1`
|
||||
ERROR 23000: CONSTRAINT `t1.a` failed for `test`.`t1`
|
||||
drop table t1;
|
||||
create table t1 (a int, b int, check (a>b));
|
||||
show create table t1;
|
||||
|
4
mysql-test/main/create_replace_tmp.result
Normal file
4
mysql-test/main/create_replace_tmp.result
Normal file
@ -0,0 +1,4 @@
|
||||
CREATE TEMPORARY TABLE t (i INT);
|
||||
CREATE or replace TABLE t AS SELECT * FROM t;
|
||||
DROP TEMPORARY TABLE t;
|
||||
DROP TABLE t;
|
4
mysql-test/main/create_replace_tmp.test
Normal file
4
mysql-test/main/create_replace_tmp.test
Normal file
@ -0,0 +1,4 @@
|
||||
CREATE TEMPORARY TABLE t (i INT);
|
||||
CREATE or replace TABLE t AS SELECT * FROM t;
|
||||
DROP TEMPORARY TABLE t;
|
||||
DROP TABLE t;
|
@ -3269,6 +3269,43 @@ select 3, 0*(@d:=@d+1) from qn where @d<1
|
||||
select * from qn;
|
||||
ERROR 42000: This version of MariaDB doesn't yet support 'mix of ALL and DISTINCT UNION operations in recursive CTE spec'
|
||||
drop table t1;
|
||||
#
|
||||
# MDEV-16629: function with recursive CTE using a base table
|
||||
#
|
||||
CREATE TABLE t1 (id int);
|
||||
INSERT INTO t1 VALUES (0), (1),(2);
|
||||
WITH recursive cte AS
|
||||
(SELECT id FROM t1 UNION SELECT 3 FROM cte)
|
||||
SELECT count(id) FROM cte;
|
||||
count(id)
|
||||
4
|
||||
CREATE OR REPLACE FUNCTION func() RETURNS int
|
||||
RETURN
|
||||
(
|
||||
WITH recursive cte AS
|
||||
(SELECT id FROM t1 UNION SELECT 3 FROM cte)
|
||||
SELECT count(id) FROM cte
|
||||
);
|
||||
SELECT func();
|
||||
func()
|
||||
4
|
||||
DROP FUNCTION func;
|
||||
DROP TABLE t1;
|
||||
#
|
||||
# MDEV-16661: function with recursive CTE using no base tables
|
||||
# (fixed by the patch for MDEV-16629)
|
||||
#
|
||||
CREATE OR REPLACE FUNCTION func() RETURNS int
|
||||
RETURN
|
||||
(
|
||||
WITH RECURSIVE cte AS
|
||||
(SELECT 1 as id UNION SELECT * FROM cte)
|
||||
SELECT count(id) FROM cte
|
||||
);
|
||||
SELECT func();
|
||||
func()
|
||||
1
|
||||
DROP FUNCTION func;
|
||||
# Start of 10.3 tests
|
||||
#
|
||||
# MDEV-14217 [db crash] Recursive CTE when SELECT includes new field
|
||||
|
@ -2283,6 +2283,47 @@ select * from qn;
|
||||
|
||||
drop table t1;
|
||||
|
||||
--echo #
|
||||
--echo # MDEV-16629: function with recursive CTE using a base table
|
||||
--echo #
|
||||
|
||||
CREATE TABLE t1 (id int);
|
||||
INSERT INTO t1 VALUES (0), (1),(2);
|
||||
|
||||
WITH recursive cte AS
|
||||
(SELECT id FROM t1 UNION SELECT 3 FROM cte)
|
||||
SELECT count(id) FROM cte;
|
||||
|
||||
CREATE OR REPLACE FUNCTION func() RETURNS int
|
||||
RETURN
|
||||
(
|
||||
WITH recursive cte AS
|
||||
(SELECT id FROM t1 UNION SELECT 3 FROM cte)
|
||||
SELECT count(id) FROM cte
|
||||
);
|
||||
|
||||
SELECT func();
|
||||
|
||||
DROP FUNCTION func;
|
||||
DROP TABLE t1;
|
||||
|
||||
--echo #
|
||||
--echo # MDEV-16661: function with recursive CTE using no base tables
|
||||
--echo # (fixed by the patch for MDEV-16629)
|
||||
--echo #
|
||||
|
||||
CREATE OR REPLACE FUNCTION func() RETURNS int
|
||||
RETURN
|
||||
(
|
||||
WITH RECURSIVE cte AS
|
||||
(SELECT 1 as id UNION SELECT * FROM cte)
|
||||
SELECT count(id) FROM cte
|
||||
);
|
||||
|
||||
SELECT func();
|
||||
|
||||
DROP FUNCTION func;
|
||||
|
||||
--echo # Start of 10.3 tests
|
||||
|
||||
--echo #
|
||||
|
23
mysql-test/main/cte_recursive_not_embedded.result
Normal file
23
mysql-test/main/cte_recursive_not_embedded.result
Normal file
@ -0,0 +1,23 @@
|
||||
#
|
||||
# MDEV-15151: function with recursive CTE using no base tables
|
||||
# (duplicate of MDEV-16661)
|
||||
#
|
||||
connection default;
|
||||
CREATE TABLE t1 (id int KEY);
|
||||
INSERT INTO t1 VALUES (0), (1),(2);
|
||||
CREATE OR REPLACE FUNCTION func() RETURNS int
|
||||
RETURN
|
||||
(
|
||||
WITH recursive cte AS
|
||||
(SELECT 1 a UNION SELECT cte.* FROM cte natural join t1)
|
||||
SELECT * FROM cte limit 1
|
||||
);
|
||||
connect con1,localhost,root,,test;
|
||||
SELECT func();
|
||||
connect con2,localhost,root,,test;
|
||||
disconnect con2;
|
||||
connection con1;
|
||||
disconnect con1;
|
||||
connection default;
|
||||
DROP FUNCTION func;
|
||||
DROP TABLE t1;
|
42
mysql-test/main/cte_recursive_not_embedded.test
Normal file
42
mysql-test/main/cte_recursive_not_embedded.test
Normal file
@ -0,0 +1,42 @@
|
||||
--source include/not_embedded.inc
|
||||
|
||||
--echo #
|
||||
--echo # MDEV-15151: function with recursive CTE using no base tables
|
||||
--echo # (duplicate of MDEV-16661)
|
||||
--echo #
|
||||
|
||||
--connection default
|
||||
|
||||
CREATE TABLE t1 (id int KEY);
|
||||
INSERT INTO t1 VALUES (0), (1),(2);
|
||||
|
||||
CREATE OR REPLACE FUNCTION func() RETURNS int
|
||||
RETURN
|
||||
(
|
||||
WITH recursive cte AS
|
||||
(SELECT 1 a UNION SELECT cte.* FROM cte natural join t1)
|
||||
SELECT * FROM cte limit 1
|
||||
);
|
||||
|
||||
--connect (con1,localhost,root,,test)
|
||||
|
||||
--let $conid= `SELECT CONNECTION_ID()`
|
||||
--send SELECT func()
|
||||
|
||||
--connect (con2,localhost,root,,test)
|
||||
--disable_query_log
|
||||
--eval KILL QUERY $conid
|
||||
--enable_query_log
|
||||
--disconnect con2
|
||||
|
||||
--disable_result_log
|
||||
--connection con1
|
||||
--error 0,ER_QUERY_INTERRUPTED
|
||||
--reap
|
||||
--disconnect con1
|
||||
--enable_result_log
|
||||
|
||||
--connection default
|
||||
|
||||
DROP FUNCTION func;
|
||||
DROP TABLE t1;
|
@ -297,7 +297,7 @@ json_quote('foo')
|
||||
show create table t1;
|
||||
Table Create Table
|
||||
t1 CREATE TABLE `t1` (
|
||||
`json_quote('foo')` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL
|
||||
`json_quote('foo')` varchar(38) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=latin1
|
||||
drop table t1;
|
||||
select json_merge('string');
|
||||
@ -748,6 +748,19 @@ SELECT * FROM t1 WHERE c IN (JSON_EXTRACT('{"a":"b"}', '$.*'));
|
||||
c
|
||||
DROP TABLE t1;
|
||||
#
|
||||
# MDEV-16814 CREATE TABLE SELECT JSON_QUOTE(multibyte_charset_expr) makes a field of a wrong length
|
||||
#
|
||||
CREATE TABLE t1 AS SELECT
|
||||
JSON_QUOTE(_latin1'foo') AS c1,
|
||||
JSON_QUOTE(_utf8'foo') AS c2;
|
||||
SHOW CREATE TABLE t1;
|
||||
Table Create Table
|
||||
t1 CREATE TABLE `t1` (
|
||||
`c1` varchar(38) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL,
|
||||
`c2` varchar(38) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=latin1
|
||||
DROP TABLE t1;
|
||||
#
|
||||
# End of 10.2 tests
|
||||
#
|
||||
#
|
||||
|
@ -412,6 +412,16 @@ INSERT INTO t1 VALUES ('foo'),('bar');
|
||||
SELECT * FROM t1 WHERE c IN (JSON_EXTRACT('{"a":"b"}', '$.*'));
|
||||
DROP TABLE t1;
|
||||
|
||||
--echo #
|
||||
--echo # MDEV-16814 CREATE TABLE SELECT JSON_QUOTE(multibyte_charset_expr) makes a field of a wrong length
|
||||
--echo #
|
||||
|
||||
CREATE TABLE t1 AS SELECT
|
||||
JSON_QUOTE(_latin1'foo') AS c1,
|
||||
JSON_QUOTE(_utf8'foo') AS c2;
|
||||
SHOW CREATE TABLE t1;
|
||||
DROP TABLE t1;
|
||||
|
||||
--echo #
|
||||
--echo # End of 10.2 tests
|
||||
--echo #
|
||||
|
@ -20,7 +20,7 @@ t1 CREATE TABLE `t1` (
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=latin1
|
||||
insert t1 values ('[]');
|
||||
insert t1 values ('a');
|
||||
ERROR 23000: CONSTRAINT `a` failed for `test`.`t1`
|
||||
ERROR 23000: CONSTRAINT `t1.a` failed for `test`.`t1`
|
||||
set timestamp=unix_timestamp('2010:11:12 13:14:15');
|
||||
create or replace table t1(a json default(json_object('now', now())));
|
||||
show create table t1;
|
||||
|
@ -296,20 +296,21 @@ DROP TABLE t1;
|
||||
# ASSERTION THD->TRANSACTION.XID_STATE.XID.IS_NULL()
|
||||
# FAILED
|
||||
#
|
||||
DROP TABLE IF EXISTS t1, t2;
|
||||
CREATE TABLE t1 (a INT) ENGINE=InnoDB;
|
||||
CREATE TABLE t2 (a INT) ENGINE=InnoDB;
|
||||
START TRANSACTION;
|
||||
INSERT INTO t1 VALUES (1);
|
||||
INSERT INTO t2 VALUES (1);
|
||||
COMMIT;
|
||||
BEGIN;
|
||||
INSERT INTO t2 VALUES (2);
|
||||
UPDATE t2 SET a=a+1;
|
||||
connect con2,localhost,root;
|
||||
XA START 'xid1';
|
||||
INSERT INTO t1 VALUES (1);
|
||||
# Sending:
|
||||
INSERT INTO t2 SELECT a FROM t1;
|
||||
DELETE FROM t2;
|
||||
connection default;
|
||||
# Waiting until INSERT ... is blocked
|
||||
DELETE FROM t1;
|
||||
connection con2;
|
||||
# Reaping: INSERT INTO t2 SELECT a FROM t1
|
||||
ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
|
||||
XA COMMIT 'xid1';
|
||||
ERROR XA102: XA_RBDEADLOCK: Transaction branch was rolled back: deadlock was detected
|
||||
|
@ -393,33 +393,30 @@ DROP TABLE t1;
|
||||
--echo # FAILED
|
||||
--echo #
|
||||
|
||||
--disable_warnings
|
||||
DROP TABLE IF EXISTS t1, t2;
|
||||
--enable_warnings
|
||||
|
||||
CREATE TABLE t1 (a INT) ENGINE=InnoDB;
|
||||
CREATE TABLE t2 (a INT) ENGINE=InnoDB;
|
||||
|
||||
START TRANSACTION;
|
||||
INSERT INTO t1 VALUES (1);
|
||||
INSERT INTO t2 VALUES (1); COMMIT;
|
||||
BEGIN;
|
||||
INSERT INTO t2 VALUES (2);
|
||||
UPDATE t2 SET a=a+1;
|
||||
|
||||
--connect (con2,localhost,root)
|
||||
XA START 'xid1';
|
||||
INSERT INTO t1 VALUES (1);
|
||||
--echo # Sending:
|
||||
--send INSERT INTO t2 SELECT a FROM t1
|
||||
--send DELETE FROM t2
|
||||
|
||||
--connection default
|
||||
let $wait_condition=
|
||||
SELECT COUNT(*) = 1 FROM information_schema.processlist
|
||||
WHERE state = "Sending data"
|
||||
AND info = "INSERT INTO t2 SELECT a FROM t1";
|
||||
--echo # Waiting until INSERT ... is blocked
|
||||
WHERE state = "Updating"
|
||||
AND info = "DELETE FROM t2";
|
||||
--source include/wait_condition.inc
|
||||
--sleep 0.1
|
||||
DELETE FROM t1;
|
||||
--send DELETE FROM t1
|
||||
|
||||
--connection con2
|
||||
--echo # Reaping: INSERT INTO t2 SELECT a FROM t1
|
||||
--error ER_LOCK_DEADLOCK
|
||||
--reap
|
||||
--error ER_XA_RBDEADLOCK
|
||||
@ -427,6 +424,7 @@ XA COMMIT 'xid1';
|
||||
|
||||
connection default;
|
||||
|
||||
reap;
|
||||
COMMIT;
|
||||
|
||||
connection con2;
|
||||
|
@ -175,8 +175,38 @@ SET DEBUG_SYNC='now WAIT_FOR halfway';
|
||||
COMMIT;
|
||||
InnoDB 0 transactions not purged
|
||||
SET DEBUG_SYNC='now SIGNAL purged';
|
||||
disconnect prevent_purge;
|
||||
connection default;
|
||||
DROP TABLE t1;
|
||||
CREATE TABLE t1 (y YEAR, vy YEAR AS (y) VIRTUAL UNIQUE, pk INT PRIMARY KEY)
|
||||
ENGINE=InnoDB;
|
||||
INSERT INTO t1 (pk,y) VALUES (1,2022);
|
||||
CREATE TABLE t2(f1 INT NOT NULL, PRIMARY KEY(f1))ENGINE=InnoDB;
|
||||
SET GLOBAL debug_dbug = '+d,ib_purge_virtual_index_callback';
|
||||
BEGIN;
|
||||
INSERT INTO t2(f1) VALUES(1);
|
||||
connection prevent_purge;
|
||||
SET DEBUG_SYNC=RESET;
|
||||
start transaction with consistent snapshot;
|
||||
connection default;
|
||||
COMMIT;
|
||||
connect truncate,localhost,root,,;
|
||||
REPLACE INTO t1(pk, y) SELECT pk,y FROM t1;
|
||||
SET DEBUG_SYNC='row_trunc_before_dict_lock SIGNAL commit WAIT_FOR release';
|
||||
TRUNCATE TABLE t1;
|
||||
connection prevent_purge;
|
||||
SET DEBUG_SYNC='now WAIT_FOR commit';
|
||||
COMMIT;
|
||||
SET DEBUG_SYNC='now SIGNAL purge_start';
|
||||
disconnect prevent_purge;
|
||||
connection default;
|
||||
SET DEBUG_SYNC='now WAIT_FOR purge_start';
|
||||
InnoDB 2 transactions not purged
|
||||
SET DEBUG_SYNC='now SIGNAL release';
|
||||
SET GLOBAL debug_dbug=@old_dbug;
|
||||
connection truncate;
|
||||
disconnect truncate;
|
||||
connection default;
|
||||
InnoDB 0 transactions not purged
|
||||
DROP TABLE t1, t2;
|
||||
set debug_sync=reset;
|
||||
SET GLOBAL innodb_purge_rseg_truncate_frequency = @saved_frequency;
|
||||
|
@ -124,7 +124,7 @@ SELECT * FROM t1;
|
||||
|
||||
DROP TABLE t1;
|
||||
|
||||
# Test adding virutal index on existing virtual column
|
||||
# Test adding index on existing virtual column
|
||||
CREATE TABLE t1 (a INT, b INT, c INT GENERATED ALWAYS AS(a+b));
|
||||
|
||||
INSERT INTO t1(a, b) VALUES (1, 1), (2, 2), (3, 3), (4, 4);
|
||||
@ -156,7 +156,9 @@ INSERT INTO t1(a, b) VALUES (8, 8);
|
||||
COMMIT;
|
||||
|
||||
--echo # wait for purge to process the deleted/updated records.
|
||||
let $wait_all_purged=2;
|
||||
--source ../../innodb/include/wait_all_purged.inc
|
||||
let $wait_all_purged=0;
|
||||
|
||||
SET DEBUG_SYNC= 'now SIGNAL purged';
|
||||
|
||||
@ -215,12 +217,54 @@ SET DEBUG_SYNC='now WAIT_FOR halfway';
|
||||
COMMIT;
|
||||
--source ../../innodb/include/wait_all_purged.inc
|
||||
SET DEBUG_SYNC='now SIGNAL purged';
|
||||
disconnect prevent_purge;
|
||||
|
||||
connection default;
|
||||
reap;
|
||||
DROP TABLE t1;
|
||||
|
||||
CREATE TABLE t1 (y YEAR, vy YEAR AS (y) VIRTUAL UNIQUE, pk INT PRIMARY KEY)
|
||||
ENGINE=InnoDB;
|
||||
|
||||
INSERT INTO t1 (pk,y) VALUES (1,2022);
|
||||
CREATE TABLE t2(f1 INT NOT NULL, PRIMARY KEY(f1))ENGINE=InnoDB;
|
||||
|
||||
SET GLOBAL debug_dbug = '+d,ib_purge_virtual_index_callback';
|
||||
|
||||
BEGIN;
|
||||
INSERT INTO t2(f1) VALUES(1);
|
||||
connection prevent_purge;
|
||||
SET DEBUG_SYNC=RESET;
|
||||
start transaction with consistent snapshot;
|
||||
connection default;
|
||||
COMMIT;
|
||||
|
||||
connect(truncate,localhost,root,,);
|
||||
REPLACE INTO t1(pk, y) SELECT pk,y FROM t1;
|
||||
SET DEBUG_SYNC='row_trunc_before_dict_lock SIGNAL commit WAIT_FOR release';
|
||||
send TRUNCATE TABLE t1;
|
||||
|
||||
connection prevent_purge;
|
||||
SET DEBUG_SYNC='now WAIT_FOR commit';
|
||||
COMMIT;
|
||||
SET DEBUG_SYNC='now SIGNAL purge_start';
|
||||
disconnect prevent_purge;
|
||||
|
||||
connection default;
|
||||
SET DEBUG_SYNC='now WAIT_FOR purge_start';
|
||||
let $wait_all_purged=2;
|
||||
--source ../../innodb/include/wait_all_purged.inc
|
||||
let $wait_all_purged=0;
|
||||
SET DEBUG_SYNC='now SIGNAL release';
|
||||
SET GLOBAL debug_dbug=@old_dbug;
|
||||
|
||||
connection truncate;
|
||||
reap;
|
||||
disconnect truncate;
|
||||
|
||||
connection default;
|
||||
--source ../../innodb/include/wait_all_purged.inc
|
||||
DROP TABLE t1, t2;
|
||||
|
||||
--source include/wait_until_count_sessions.inc
|
||||
set debug_sync=reset;
|
||||
SET GLOBAL innodb_purge_rseg_truncate_frequency = @saved_frequency;
|
||||
|
@ -1,12 +1,18 @@
|
||||
# Wait for everything to be purged.
|
||||
# The user should have set innodb_purge_rseg_truncate_frequency=1.
|
||||
|
||||
if (!$wait_all_purged)
|
||||
{
|
||||
let $wait_all_purged= 0;
|
||||
}
|
||||
let $remaining_expect= `select concat('InnoDB ',$wait_all_purged)`;
|
||||
|
||||
let $wait_counter= 300;
|
||||
while ($wait_counter)
|
||||
{
|
||||
--replace_regex /.*History list length ([0-9]+).*/\1/
|
||||
let $remaining= `SHOW ENGINE INNODB STATUS`;
|
||||
if ($remaining == 'InnoDB 0')
|
||||
if ($remaining == $remaining_expect)
|
||||
{
|
||||
let $wait_counter= 0;
|
||||
}
|
||||
|
@ -45,7 +45,7 @@ trx_last_foreign_key_error varchar(256) YES NULL
|
||||
trx_is_read_only int(1) NO 0
|
||||
trx_autocommit_non_locking int(1) NO 0
|
||||
trx_state trx_weight trx_tables_in_use trx_tables_locked trx_rows_locked trx_rows_modified trx_concurrency_tickets trx_isolation_level trx_unique_checks trx_foreign_key_checks
|
||||
RUNNING 4 0 1 7 1 0 REPEATABLE READ 1 1
|
||||
RUNNING 3 0 1 5 1 0 REPEATABLE READ 1 1
|
||||
trx_isolation_level trx_unique_checks trx_foreign_key_checks
|
||||
SERIALIZABLE 0 0
|
||||
trx_state trx_isolation_level trx_last_foreign_key_error
|
||||
|
@ -661,7 +661,21 @@ SELECT NAME, COUNT > 0 FROM INFORMATION_SCHEMA.INNODB_METRICS WHERE NAME
|
||||
LIKE 'buffer_page_written_index_leaf';
|
||||
NAME COUNT > 0
|
||||
buffer_page_written_index_leaf 1
|
||||
DROP TABLE t1;
|
||||
CREATE TABLE t1(id INT PRIMARY KEY, a INT, b CHAR(1), UNIQUE KEY u(a,b))
|
||||
ENGINE=InnoDB;
|
||||
SET @start = (SELECT COUNT FROM INFORMATION_SCHEMA.INNODB_METRICS WHERE NAME
|
||||
= 'lock_rec_lock_created');
|
||||
BEGIN;
|
||||
INSERT INTO t1 VALUES(1,1,'a'),(2,9999,'b'),(3,10000,'c'),(4,4,'d');
|
||||
DELETE FROM t1 WHERE a = 9999 AND b='b';
|
||||
COMMIT;
|
||||
SET @end = (SELECT COUNT FROM INFORMATION_SCHEMA.INNODB_METRICS WHERE NAME
|
||||
= 'lock_rec_lock_created');
|
||||
SELECT @end - @start;
|
||||
@end - @start
|
||||
0
|
||||
DROP TABLE t1;
|
||||
SET GLOBAL innodb_monitor_enable=default;
|
||||
SET GLOBAL innodb_monitor_disable=default;
|
||||
SET GLOBAL innodb_monitor_reset_all=default;
|
||||
DROP TABLE t1;
|
||||
|
@ -192,25 +192,9 @@ ROLLBACK;
|
||||
disconnect stop_purge;
|
||||
|
||||
# Wait for purge to empty the table.
|
||||
# (This is based on wait_all_purged.inc, but there are 2 transactions
|
||||
# from the pending ALTER TABLE t1 FORCE.)
|
||||
|
||||
let $wait_counter= 300;
|
||||
while ($wait_counter)
|
||||
{
|
||||
--replace_regex /.*History list length ([0-9]+).*/\1/
|
||||
let $remaining= `SHOW ENGINE INNODB STATUS`;
|
||||
if ($remaining == 'InnoDB 2')
|
||||
{
|
||||
let $wait_counter= 0;
|
||||
}
|
||||
if ($wait_counter)
|
||||
{
|
||||
real_sleep 0.1;
|
||||
dec $wait_counter;
|
||||
}
|
||||
}
|
||||
echo $remaining transactions not purged;
|
||||
let $wait_all_purged=2;
|
||||
--source include/wait_all_purged.inc
|
||||
let $wait_all_purged=0;
|
||||
|
||||
SET DEBUG_SYNC='now SIGNAL logged';
|
||||
disconnect ddl;
|
||||
|
@ -422,10 +422,27 @@ UNLOCK TABLES;
|
||||
SELECT NAME, COUNT > 0 FROM INFORMATION_SCHEMA.INNODB_METRICS WHERE NAME
|
||||
LIKE 'buffer_page_written_index_leaf';
|
||||
|
||||
DROP TABLE t1;
|
||||
|
||||
CREATE TABLE t1(id INT PRIMARY KEY, a INT, b CHAR(1), UNIQUE KEY u(a,b))
|
||||
ENGINE=InnoDB;
|
||||
|
||||
SET @start = (SELECT COUNT FROM INFORMATION_SCHEMA.INNODB_METRICS WHERE NAME
|
||||
= 'lock_rec_lock_created');
|
||||
|
||||
BEGIN;
|
||||
INSERT INTO t1 VALUES(1,1,'a'),(2,9999,'b'),(3,10000,'c'),(4,4,'d');
|
||||
DELETE FROM t1 WHERE a = 9999 AND b='b';
|
||||
COMMIT;
|
||||
|
||||
SET @end = (SELECT COUNT FROM INFORMATION_SCHEMA.INNODB_METRICS WHERE NAME
|
||||
= 'lock_rec_lock_created');
|
||||
SELECT @end - @start;
|
||||
|
||||
DROP TABLE t1;
|
||||
|
||||
--disable_warnings
|
||||
SET GLOBAL innodb_monitor_enable=default;
|
||||
SET GLOBAL innodb_monitor_disable=default;
|
||||
SET GLOBAL innodb_monitor_reset_all=default;
|
||||
--enable_warnings
|
||||
|
||||
DROP TABLE t1;
|
||||
|
@ -2,6 +2,7 @@ call mtr.add_suppression("InnoDB: New log files created");
|
||||
CREATE TABLE t(i INT) ENGINE INNODB ENCRYPTED=YES;
|
||||
INSERT INTO t VALUES(1);
|
||||
# Create full backup , modify table, then create incremental/differential backup
|
||||
SET GLOBAL innodb_flush_log_at_trx_commit = 1;
|
||||
INSERT INTO t VALUES(2);
|
||||
SELECT * FROM t;
|
||||
i
|
||||
|
@ -20,6 +20,7 @@ echo # Create full backup , modify table, then create incremental/differential b
|
||||
exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --backup --target-dir=$basedir;
|
||||
--enable_result_log
|
||||
|
||||
SET GLOBAL innodb_flush_log_at_trx_commit = 1;
|
||||
INSERT INTO t VALUES(2);
|
||||
SELECT * FROM t;
|
||||
|
||||
|
@ -1 +1 @@
|
||||
--innodb --loose-changed_page_bitmaps --innodb-sys-tables
|
||||
--innodb --loose-changed_page_bitmaps --innodb-sys-tables --innodb-flush-log-at-trx-commit=2
|
||||
|
@ -5,9 +5,6 @@ call mtr.add_suppression("InnoDB: If you are installing InnoDB, remember that yo
|
||||
call mtr.add_suppression("InnoDB: Ignoring tablespace for `test`\\.`t21` because it could not be opened");
|
||||
call mtr.add_suppression("InnoDB: Cannot open datafile for read-only: ");
|
||||
call mtr.add_suppression("Table .* in the InnoDB data dictionary has tablespace id .*, but tablespace with that id or name does not exist");
|
||||
SELECT @@GLOBAL.innodb_flush_log_at_trx_commit;
|
||||
@@GLOBAL.innodb_flush_log_at_trx_commit
|
||||
1
|
||||
CREATE TABLE t1(i INT PRIMARY KEY auto_increment, a int) ENGINE INNODB;
|
||||
ALTER TABLE t1 FORCE, ALGORITHM=INPLACE;
|
||||
# Fails during full backup
|
||||
|
@ -10,7 +10,6 @@ call mtr.add_suppression("Table .* in the InnoDB data dictionary has tablespace
|
||||
let $basedir=$MYSQLTEST_VARDIR/tmp/backup;
|
||||
let $incremental_dir=$MYSQLTEST_VARDIR/tmp/backup_inc1;
|
||||
|
||||
SELECT @@GLOBAL.innodb_flush_log_at_trx_commit;
|
||||
CREATE TABLE t1(i INT PRIMARY KEY auto_increment, a int) ENGINE INNODB;
|
||||
--source ../../suite/innodb/include/no_checkpoint_start.inc
|
||||
ALTER TABLE t1 FORCE, ALGORITHM=INPLACE;
|
||||
|
@ -6,9 +6,16 @@ eval LOAD DATA INFILE '$LOAD_FILE' INTO TABLE t1;
|
||||
eval LOAD DATA INFILE '$LOAD_FILE' INTO TABLE t1;
|
||||
SELECT * FROM t1 ORDER BY word LIMIT 10;
|
||||
|
||||
#
|
||||
# Save password row for root
|
||||
#
|
||||
|
||||
create temporary table tmp select * from mysql.user where host="localhost" and user="root";
|
||||
|
||||
#
|
||||
# Test slave with wrong password
|
||||
#
|
||||
|
||||
save_master_pos;
|
||||
connection slave;
|
||||
sync_with_master;
|
||||
@ -24,6 +31,7 @@ connection master;
|
||||
real_sleep 2;
|
||||
SET PASSWORD FOR root@"localhost" = PASSWORD('');
|
||||
# Give slave time to connect (will retry every second)
|
||||
|
||||
sleep 2;
|
||||
|
||||
CREATE TABLE t3(n INT);
|
||||
@ -80,4 +88,9 @@ SELECT n FROM t1;
|
||||
|
||||
connection master;
|
||||
DROP TABLE t1;
|
||||
|
||||
# resttore old passwords
|
||||
replace into mysql.user select * from tmp;
|
||||
drop temporary table tmp;
|
||||
|
||||
sync_slave_with_master;
|
||||
|
9
mysql-test/suite/rpl/r/rpl_15867.result
Normal file
9
mysql-test/suite/rpl/r/rpl_15867.result
Normal file
@ -0,0 +1,9 @@
|
||||
include/master-slave.inc
|
||||
[connection master]
|
||||
CREATE TEMPORARY TABLE t (i INT);
|
||||
CREATE TABLE t AS SELECT * FROM t;
|
||||
connection slave;
|
||||
connection master;
|
||||
DROP TEMPORARY TABLE t;
|
||||
DROP TABLE t;
|
||||
include/rpl_end.inc
|
@ -15,6 +15,7 @@ Aaron
|
||||
Aaron
|
||||
Ababa
|
||||
Ababa
|
||||
create temporary table tmp select * from mysql.user where host="localhost" and user="root";
|
||||
connection slave;
|
||||
STOP SLAVE;
|
||||
connection master;
|
||||
@ -65,5 +66,7 @@ n
|
||||
3456
|
||||
connection master;
|
||||
DROP TABLE t1;
|
||||
replace into mysql.user select * from tmp;
|
||||
drop temporary table tmp;
|
||||
connection slave;
|
||||
include/rpl_end.inc
|
||||
|
11
mysql-test/suite/rpl/t/rpl_15867.test
Normal file
11
mysql-test/suite/rpl/t/rpl_15867.test
Normal file
@ -0,0 +1,11 @@
|
||||
--source include/master-slave.inc
|
||||
CREATE TEMPORARY TABLE t (i INT);
|
||||
CREATE TABLE t AS SELECT * FROM t;
|
||||
|
||||
--sync_slave_with_master
|
||||
|
||||
# Cleanup
|
||||
--connection master
|
||||
DROP TEMPORARY TABLE t;
|
||||
DROP TABLE t;
|
||||
--source include/rpl_end.inc
|
@ -1326,9 +1326,9 @@ READ_ONLY YES
|
||||
COMMAND_LINE_ARGUMENT NONE
|
||||
VARIABLE_NAME INNODB_LOCK_SCHEDULE_ALGORITHM
|
||||
SESSION_VALUE NULL
|
||||
GLOBAL_VALUE vats
|
||||
GLOBAL_VALUE fcfs
|
||||
GLOBAL_VALUE_ORIGIN COMPILE-TIME
|
||||
DEFAULT_VALUE vats
|
||||
DEFAULT_VALUE fcfs
|
||||
VARIABLE_SCOPE GLOBAL
|
||||
VARIABLE_TYPE ENUM
|
||||
VARIABLE_COMMENT The algorithm Innodb uses for deciding which locks to grant next when a lock is released. Possible values are FCFS grant the locks in First-Come-First-Served order; VATS use the Variance-Aware-Transaction-Scheduling algorithm, which uses an Eldest-Transaction-First heuristic.
|
||||
|
@ -7755,10 +7755,9 @@ void Field_varstring::sql_type(String &res) const
|
||||
size_t length;
|
||||
|
||||
length= cs->cset->snprintf(cs,(char*) res.ptr(),
|
||||
res.alloced_length(), "%s(%d)",
|
||||
res.alloced_length(), "%s(%u)",
|
||||
(has_charset() ? "varchar" : "varbinary"),
|
||||
(int) field_length / charset()->mbmaxlen -
|
||||
MY_TEST(compression_method()));
|
||||
(uint) char_length());
|
||||
res.length(length);
|
||||
if ((thd->variables.sql_mode & (MODE_MYSQL323 | MODE_MYSQL40)) &&
|
||||
has_charset() && (charset()->state & MY_CS_BINSORT))
|
||||
|
@ -575,7 +575,7 @@ bool Item_func_json_quote::fix_length_and_dec()
|
||||
Odd but realistic worst case is when all characters
|
||||
of the argument turn into '\uXXXX\uXXXX', which is 12.
|
||||
*/
|
||||
max_length= args[0]->max_length * 12 + 2;
|
||||
fix_char_length_ulonglong((ulonglong) args[0]->max_char_length() * 12 + 2);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include "sql_array.h" // Dynamic_array
|
||||
#include "log_event.h" // Query_log_event
|
||||
#include "sql_derived.h" // mysql_handle_derived
|
||||
#include "sql_cte.h"
|
||||
#include "sql_select.h" // Virtual_tmp_table
|
||||
|
||||
#ifdef USE_PRAGMA_IMPLEMENTATION
|
||||
@ -3287,7 +3288,8 @@ sp_lex_keeper::reset_lex_and_exec_core(THD *thd, uint *nextp,
|
||||
#endif
|
||||
|
||||
if (open_tables)
|
||||
res= instr->exec_open_and_lock_tables(thd, m_lex->query_tables);
|
||||
res= check_dependencies_in_with_clauses(m_lex->with_clauses_list) ||
|
||||
instr->exec_open_and_lock_tables(thd, m_lex->query_tables);
|
||||
|
||||
if (likely(!res))
|
||||
{
|
||||
|
@ -1039,6 +1039,12 @@ retry:
|
||||
if (res->table && (res->table == table->table))
|
||||
continue;
|
||||
|
||||
/* Skip if table is tmp table */
|
||||
if (check_flag & CHECK_DUP_SKIP_TEMP_TABLE &&
|
||||
res->table && res->table->s->tmp_table != NO_TMP_TABLE)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (check_flag & CHECK_DUP_FOR_CREATE)
|
||||
DBUG_RETURN(res);
|
||||
|
||||
|
@ -64,6 +64,7 @@ enum find_item_error_report_type {REPORT_ALL_ERRORS, REPORT_EXCEPT_NOT_FOUND,
|
||||
/* Flag bits for unique_table() */
|
||||
#define CHECK_DUP_ALLOW_DIFFERENT_ALIAS 1
|
||||
#define CHECK_DUP_FOR_CREATE 2
|
||||
#define CHECK_DUP_SKIP_TEMP_TABLE 4
|
||||
|
||||
uint get_table_def_key(const TABLE_LIST *table_list, const char **key);
|
||||
TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type update,
|
||||
|
@ -4677,13 +4677,6 @@ TABLE *open_purge_table(THD *thd, const char *db, size_t dblen,
|
||||
DBUG_RETURN(error ? NULL : tl->table);
|
||||
}
|
||||
|
||||
TABLE *get_purge_table(THD *thd)
|
||||
{
|
||||
/* see above, at most one table can be opened */
|
||||
DBUG_ASSERT(thd->open_tables == NULL || thd->open_tables->next == NULL);
|
||||
return thd->open_tables;
|
||||
}
|
||||
|
||||
|
||||
/** Find an open table in the list of prelocked tabled
|
||||
|
||||
|
@ -4199,7 +4199,8 @@ mysql_execute_command(THD *thd)
|
||||
TABLE_LIST *duplicate;
|
||||
if (unlikely((duplicate= unique_table(thd, lex->query_tables,
|
||||
lex->query_tables->next_global,
|
||||
CHECK_DUP_FOR_CREATE))))
|
||||
CHECK_DUP_FOR_CREATE |
|
||||
CHECK_DUP_SKIP_TEMP_TABLE))))
|
||||
{
|
||||
update_non_unique_table_error(lex->query_tables, "CREATE",
|
||||
duplicate);
|
||||
|
12
sql/table.cc
12
sql/table.cc
@ -5275,8 +5275,18 @@ int TABLE::verify_constraints(bool ignore_failure)
|
||||
if (((*chk)->expr->val_int() == 0 && !(*chk)->expr->null_value) ||
|
||||
in_use->is_error())
|
||||
{
|
||||
StringBuffer<MAX_FIELD_WIDTH> field_error(system_charset_info);
|
||||
enum_vcol_info_type vcol_type= (*chk)->get_vcol_type();
|
||||
DBUG_ASSERT(vcol_type == VCOL_CHECK_TABLE ||
|
||||
vcol_type == VCOL_CHECK_FIELD);
|
||||
if (vcol_type == VCOL_CHECK_FIELD)
|
||||
{
|
||||
field_error.append(s->table_name.str);
|
||||
field_error.append(".");
|
||||
}
|
||||
field_error.append((*chk)->name.str);
|
||||
my_error(ER_CONSTRAINT_FAILED,
|
||||
MYF(ignore_failure ? ME_WARNING : 0), (*chk)->name.str,
|
||||
MYF(ignore_failure ? ME_WARNING : 0), field_error.c_ptr(),
|
||||
s->db.str, s->error_table_name());
|
||||
return ignore_failure ? VIEW_CHECK_SKIP : VIEW_CHECK_ERROR;
|
||||
}
|
||||
|
@ -570,10 +570,9 @@ static
|
||||
bool
|
||||
btr_search_update_block_hash_info(btr_search_t* info, buf_block_t* block)
|
||||
{
|
||||
ut_ad(!btr_search_own_any(RW_LOCK_S));
|
||||
ut_ad(!btr_search_own_any(RW_LOCK_X));
|
||||
ut_ad(rw_lock_own(&block->lock, RW_LOCK_S)
|
||||
|| rw_lock_own(&block->lock, RW_LOCK_X));
|
||||
ut_ad(!btr_search_own_any());
|
||||
ut_ad(rw_lock_own_flagged(&block->lock,
|
||||
RW_LOCK_FLAG_X | RW_LOCK_FLAG_S));
|
||||
|
||||
info->last_hash_succ = FALSE;
|
||||
|
||||
@ -648,8 +647,8 @@ btr_search_update_hash_ref(
|
||||
|
||||
ut_ad(cursor->flag == BTR_CUR_HASH_FAIL);
|
||||
ut_ad(rw_lock_own(btr_get_search_latch(cursor->index), RW_LOCK_X));
|
||||
ut_ad(rw_lock_own(&(block->lock), RW_LOCK_S)
|
||||
|| rw_lock_own(&(block->lock), RW_LOCK_X));
|
||||
ut_ad(rw_lock_own_flagged(&block->lock,
|
||||
RW_LOCK_FLAG_X | RW_LOCK_FLAG_S));
|
||||
ut_ad(page_align(btr_cur_get_rec(cursor)) == block->frame);
|
||||
ut_ad(page_is_leaf(block->frame));
|
||||
assert_block_ahi_valid(block);
|
||||
@ -887,8 +886,8 @@ btr_search_guess_on_hash(
|
||||
btr_cur_t cursor2;
|
||||
btr_pcur_t pcur;
|
||||
#endif
|
||||
ut_ad(!ahi_latch || rw_lock_own(ahi_latch, RW_LOCK_S)
|
||||
|| rw_lock_own(ahi_latch, RW_LOCK_X));
|
||||
ut_ad(!ahi_latch || rw_lock_own_flagged(
|
||||
ahi_latch, RW_LOCK_FLAG_X | RW_LOCK_FLAG_S));
|
||||
|
||||
if (!btr_search_enabled) {
|
||||
return(FALSE);
|
||||
@ -1109,8 +1108,8 @@ retry:
|
||||
|
||||
ut_ad(block->page.buf_fix_count == 0
|
||||
|| buf_block_get_state(block) == BUF_BLOCK_REMOVE_HASH
|
||||
|| rw_lock_own(&block->lock, RW_LOCK_S)
|
||||
|| rw_lock_own(&block->lock, RW_LOCK_X));
|
||||
|| rw_lock_own_flagged(&block->lock,
|
||||
RW_LOCK_FLAG_X | RW_LOCK_FLAG_S));
|
||||
ut_ad(page_is_leaf(block->frame));
|
||||
|
||||
/* We must not dereference index here, because it could be freed
|
||||
@ -1307,7 +1306,7 @@ void btr_search_drop_page_hash_when_freed(const page_id_t& page_id)
|
||||
/* In all our callers, the table handle should
|
||||
be open, or we should be in the process of
|
||||
dropping the table (preventing eviction). */
|
||||
ut_ad(index->table->n_ref_count > 0
|
||||
ut_ad(index->table->get_ref_count() > 0
|
||||
|| mutex_own(&dict_sys->mutex));
|
||||
btr_search_drop_page_hash_index(block);
|
||||
}
|
||||
@ -1363,8 +1362,8 @@ btr_search_build_page_hash_index(
|
||||
ut_a(!dict_index_is_ibuf(index));
|
||||
ut_ad(page_is_leaf(block->frame));
|
||||
|
||||
ut_ad(rw_lock_own(&(block->lock), RW_LOCK_S)
|
||||
|| rw_lock_own(&(block->lock), RW_LOCK_X));
|
||||
ut_ad(rw_lock_own_flagged(&block->lock,
|
||||
RW_LOCK_FLAG_X | RW_LOCK_FLAG_S));
|
||||
|
||||
rw_lock_s_lock(ahi_latch);
|
||||
|
||||
@ -1531,8 +1530,8 @@ btr_search_info_update_slow(btr_search_t* info, btr_cur_t* cursor)
|
||||
{
|
||||
rw_lock_t* ahi_latch = btr_get_search_latch(cursor->index);
|
||||
|
||||
ut_ad(!rw_lock_own(ahi_latch, RW_LOCK_S));
|
||||
ut_ad(!rw_lock_own(ahi_latch, RW_LOCK_X));
|
||||
ut_ad(!rw_lock_own_flagged(ahi_latch,
|
||||
RW_LOCK_FLAG_X | RW_LOCK_FLAG_S));
|
||||
|
||||
buf_block_t* block = btr_cur_get_block(cursor);
|
||||
|
||||
|
@ -4498,8 +4498,9 @@ loop:
|
||||
case BUF_GET_IF_IN_POOL_OR_WATCH:
|
||||
case BUF_PEEK_IF_IN_POOL:
|
||||
case BUF_EVICT_IF_IN_POOL:
|
||||
ut_ad(!rw_lock_own(hash_lock, RW_LOCK_X));
|
||||
ut_ad(!rw_lock_own(hash_lock, RW_LOCK_S));
|
||||
ut_ad(!rw_lock_own_flagged(
|
||||
hash_lock,
|
||||
RW_LOCK_FLAG_X | RW_LOCK_FLAG_S));
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
@ -4840,8 +4841,8 @@ evict_from_pool:
|
||||
ut_ad(block == fix_block);
|
||||
ut_ad(fix_block->page.buf_fix_count > 0);
|
||||
|
||||
ut_ad(!rw_lock_own(hash_lock, RW_LOCK_X));
|
||||
ut_ad(!rw_lock_own(hash_lock, RW_LOCK_S));
|
||||
ut_ad(!rw_lock_own_flagged(hash_lock,
|
||||
RW_LOCK_FLAG_X | RW_LOCK_FLAG_S));
|
||||
|
||||
ut_ad(buf_block_get_state(fix_block) == BUF_BLOCK_FILE_PAGE);
|
||||
|
||||
@ -5015,8 +5016,8 @@ evict_from_pool:
|
||||
ut_a(ibuf_count_get(fix_block->page.id) == 0);
|
||||
#endif
|
||||
|
||||
ut_ad(!rw_lock_own(hash_lock, RW_LOCK_X));
|
||||
ut_ad(!rw_lock_own(hash_lock, RW_LOCK_S));
|
||||
ut_ad(!rw_lock_own_flagged(hash_lock,
|
||||
RW_LOCK_FLAG_X | RW_LOCK_FLAG_S));
|
||||
|
||||
return(fix_block);
|
||||
}
|
||||
@ -5688,8 +5689,8 @@ func_exit:
|
||||
ibuf_mtr_commit(&mtr);
|
||||
}
|
||||
|
||||
ut_ad(!rw_lock_own(hash_lock, RW_LOCK_X));
|
||||
ut_ad(!rw_lock_own(hash_lock, RW_LOCK_S));
|
||||
ut_ad(!rw_lock_own_flagged(hash_lock,
|
||||
RW_LOCK_FLAG_X | RW_LOCK_FLAG_S));
|
||||
ut_ad(!bpage || buf_page_in_file(bpage));
|
||||
|
||||
return(bpage);
|
||||
|
@ -967,7 +967,7 @@ buf_flush_init_for_writing(
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t checksum= 0;
|
||||
uint32_t checksum = BUF_NO_CHECKSUM_MAGIC;
|
||||
|
||||
switch (srv_checksum_algorithm_t(srv_checksum_algorithm)) {
|
||||
case SRV_CHECKSUM_ALGORITHM_INNODB:
|
||||
@ -990,7 +990,6 @@ buf_flush_init_for_writing(
|
||||
break;
|
||||
case SRV_CHECKSUM_ALGORITHM_NONE:
|
||||
case SRV_CHECKSUM_ALGORITHM_STRICT_NONE:
|
||||
checksum = BUF_NO_CHECKSUM_MAGIC;
|
||||
mach_write_to_4(page + FIL_PAGE_SPACE_OR_CHKSUM,
|
||||
checksum);
|
||||
break;
|
||||
|
@ -1629,8 +1629,8 @@ func_exit:
|
||||
}
|
||||
|
||||
/* buf_LRU_block_remove_hashed() releases the hash_lock */
|
||||
ut_ad(!rw_lock_own(hash_lock, RW_LOCK_X)
|
||||
&& !rw_lock_own(hash_lock, RW_LOCK_S));
|
||||
ut_ad(!rw_lock_own_flagged(hash_lock,
|
||||
RW_LOCK_FLAG_X | RW_LOCK_FLAG_S));
|
||||
|
||||
/* We have just freed a BUF_BLOCK_FILE_PAGE. If b != NULL
|
||||
then it was a compressed page with an uncompressed frame and
|
||||
@ -2183,9 +2183,8 @@ buf_LRU_free_one_page(
|
||||
}
|
||||
|
||||
/* buf_LRU_block_remove_hashed() releases hash_lock and block_mutex */
|
||||
ut_ad(!rw_lock_own(hash_lock, RW_LOCK_X)
|
||||
&& !rw_lock_own(hash_lock, RW_LOCK_S));
|
||||
|
||||
ut_ad(!rw_lock_own_flagged(hash_lock,
|
||||
RW_LOCK_FLAG_X | RW_LOCK_FLAG_S));
|
||||
ut_ad(!mutex_own(block_mutex));
|
||||
}
|
||||
|
||||
|
@ -418,7 +418,7 @@ dict_table_try_drop_aborted(
|
||||
dict_table_t* table, /*!< in: table, or NULL if it
|
||||
needs to be looked up again */
|
||||
table_id_t table_id, /*!< in: table identifier */
|
||||
ulint ref_count) /*!< in: expected table->n_ref_count */
|
||||
int32 ref_count) /*!< in: expected table->n_ref_count */
|
||||
{
|
||||
trx_t* trx;
|
||||
|
||||
@ -1328,7 +1328,7 @@ static
|
||||
ibool
|
||||
dict_table_can_be_evicted(
|
||||
/*======================*/
|
||||
const dict_table_t* table) /*!< in: table to test */
|
||||
dict_table_t* table) /*!< in: table to test */
|
||||
{
|
||||
ut_ad(mutex_own(&dict_sys->mutex));
|
||||
ut_ad(rw_lock_own(dict_operation_lock, RW_LOCK_X));
|
||||
@ -6872,6 +6872,7 @@ dict_foreign_qualify_index(
|
||||
}
|
||||
|
||||
if (field->col->is_virtual()) {
|
||||
col_name = "";
|
||||
for (ulint j = 0; j < table->n_v_def; j++) {
|
||||
col_name = dict_table_get_v_col_name(table, j);
|
||||
if (innobase_strcasecmp(field->name,col_name) == 0) {
|
||||
|
@ -1479,7 +1479,6 @@ fil_space_create(
|
||||
rw_lock_create(fil_space_latch_key, &space->latch, SYNC_FSP);
|
||||
|
||||
if (space->purpose == FIL_TYPE_TEMPORARY) {
|
||||
ut_d(space->latch.set_temp_fsp());
|
||||
/* SysTablespace::open_or_create() would pass
|
||||
size!=0 to fil_node_create(), so first_time_open
|
||||
would not hold in fil_node_open_file(), and we
|
||||
|
@ -257,9 +257,8 @@ rtr_pcur_getnext_from_path(
|
||||
rtr_info->tree_savepoints[tree_idx] = mtr_set_savepoint(mtr);
|
||||
|
||||
#ifdef UNIV_RTR_DEBUG
|
||||
ut_ad(!(rw_lock_own(&btr_cur->page_cur.block->lock, RW_LOCK_X)
|
||||
||
|
||||
rw_lock_own(&btr_cur->page_cur.block->lock, RW_LOCK_S))
|
||||
ut_ad(!(rw_lock_own_flagged(&btr_cur->page_cur.block->lock,
|
||||
RW_LOCK_FLAG_X | RW_LOCK_FLAG_S))
|
||||
|| my_latch_mode == BTR_MODIFY_TREE
|
||||
|| my_latch_mode == BTR_CONT_MODIFY_TREE
|
||||
|| !page_is_leaf(buf_block_get_frame(
|
||||
|
@ -128,7 +128,7 @@ void destroy_thd(MYSQL_THD thd);
|
||||
void reset_thd(MYSQL_THD thd);
|
||||
TABLE *open_purge_table(THD *thd, const char *db, size_t dblen,
|
||||
const char *tb, size_t tblen);
|
||||
TABLE *get_purge_table(THD *thd);
|
||||
void close_thread_tables(THD* thd);
|
||||
|
||||
#ifdef MYSQL_DYNAMIC_PLUGIN
|
||||
#define tc_size 400
|
||||
@ -2969,7 +2969,7 @@ ha_innobase::update_thd(
|
||||
m_user_thd, thd));
|
||||
|
||||
/* The table should have been opened in ha_innobase::open(). */
|
||||
ut_ad(m_prebuilt->table->n_ref_count > 0);
|
||||
DBUG_ASSERT(m_prebuilt->table->get_ref_count() > 0);
|
||||
|
||||
trx_t* trx = check_trx_exists(thd);
|
||||
|
||||
@ -13913,7 +13913,7 @@ ha_innobase::info_low(
|
||||
m_prebuilt->trx->op_info = "returning various info to MariaDB";
|
||||
|
||||
ib_table = m_prebuilt->table;
|
||||
ut_ad(ib_table->n_ref_count > 0);
|
||||
DBUG_ASSERT(ib_table->get_ref_count() > 0);
|
||||
|
||||
if (flag & HA_STATUS_TIME) {
|
||||
if (is_analyze || innobase_stats_on_metadata) {
|
||||
@ -19478,7 +19478,7 @@ static MYSQL_SYSVAR_ENUM(lock_schedule_algorithm, innodb_lock_schedule_algorithm
|
||||
" VATS"
|
||||
" use the Variance-Aware-Transaction-Scheduling algorithm, which"
|
||||
" uses an Eldest-Transaction-First heuristic.",
|
||||
NULL, NULL, INNODB_LOCK_SCHEDULE_ALGORITHM_VATS,
|
||||
NULL, NULL, INNODB_LOCK_SCHEDULE_ALGORITHM_FCFS,
|
||||
&innodb_lock_schedule_algorithm_typelib);
|
||||
|
||||
static MYSQL_SYSVAR_ULONG(buffer_pool_instances, srv_buf_pool_instances,
|
||||
@ -20618,63 +20618,151 @@ innobase_index_cond(
|
||||
return handler_index_cond_check(file);
|
||||
}
|
||||
|
||||
|
||||
/** Find or open a mysql table for the virtual column template
|
||||
@param[in] thd mysql thread handle
|
||||
@param[in,out] table InnoDB table whose virtual column template is to be updated
|
||||
@return TABLE if successful or NULL */
|
||||
static TABLE *
|
||||
innobase_find_mysql_table_for_vc(
|
||||
/*=============================*/
|
||||
THD* thd,
|
||||
dict_table_t* table)
|
||||
/** Parse the table file name into table name and database name.
|
||||
@param[in] tbl_name InnoDB table name
|
||||
@param[out] dbname database name buffer (NAME_LEN + 1 bytes)
|
||||
@param[out] tblname table name buffer (NAME_LEN + 1 bytes)
|
||||
@param[out] dbnamelen database name length
|
||||
@param[out] tblnamelen table name length
|
||||
@return true if the table name is parsed properly. */
|
||||
static bool table_name_parse(
|
||||
const table_name_t& tbl_name,
|
||||
char* dbname,
|
||||
char* tblname,
|
||||
ulint& dbnamelen,
|
||||
ulint& tblnamelen)
|
||||
{
|
||||
TABLE *mysql_table;
|
||||
bool bg_thread = THDVAR(thd, background_thread);
|
||||
dbnamelen = dict_get_db_name_len(tbl_name.m_name);
|
||||
char db_buf[MAX_DATABASE_NAME_LEN + 1];
|
||||
char tbl_buf[MAX_TABLE_NAME_LEN + 1];
|
||||
|
||||
if (bg_thread) {
|
||||
if ((mysql_table = get_purge_table(thd))) {
|
||||
return mysql_table;
|
||||
ut_ad(dbnamelen > 0);
|
||||
ut_ad(dbnamelen <= MAX_DATABASE_NAME_LEN);
|
||||
|
||||
memcpy(db_buf, tbl_name.m_name, dbnamelen);
|
||||
db_buf[dbnamelen] = 0;
|
||||
|
||||
tblnamelen = strlen(tbl_name.m_name + dbnamelen + 1);
|
||||
memcpy(tbl_buf, tbl_name.m_name + dbnamelen + 1, tblnamelen);
|
||||
tbl_buf[tblnamelen] = 0;
|
||||
|
||||
filename_to_tablename(db_buf, dbname, MAX_DATABASE_NAME_LEN + 1, true);
|
||||
|
||||
if (tblnamelen > TEMP_FILE_PREFIX_LENGTH
|
||||
&& !strncmp(tbl_buf, TEMP_FILE_PREFIX, TEMP_FILE_PREFIX_LENGTH)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (char *is_part = strchr(tbl_buf, '#')) {
|
||||
*is_part = '\0';
|
||||
}
|
||||
|
||||
filename_to_tablename(tbl_buf, tblname, MAX_TABLE_NAME_LEN + 1, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/** Acquire metadata lock and MariaDB table handle for an InnoDB table.
|
||||
@param[in,out] thd thread handle
|
||||
@param[in,out] table InnoDB table
|
||||
@return MariaDB table handle
|
||||
@retval NULL if the table does not exist, is unaccessible or corrupted. */
|
||||
static TABLE* innodb_acquire_mdl(THD* thd, dict_table_t* table)
|
||||
{
|
||||
char db_buf[NAME_LEN + 1], db_buf1[NAME_LEN + 1];
|
||||
char tbl_buf[NAME_LEN + 1], tbl_buf1[NAME_LEN + 1];
|
||||
ulint db_buf_len, db_buf1_len;
|
||||
ulint tbl_buf_len, tbl_buf1_len;
|
||||
|
||||
if (!table_name_parse(table->name, db_buf, tbl_buf,
|
||||
db_buf_len, tbl_buf_len)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const table_id_t table_id = table->id;
|
||||
retry_mdl:
|
||||
const bool unaccessible = !table->is_readable() || table->corrupted;
|
||||
table->release();
|
||||
|
||||
if (unaccessible) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
TABLE* mariadb_table = open_purge_table(thd, db_buf, db_buf_len,
|
||||
tbl_buf, tbl_buf_len);
|
||||
|
||||
table = dict_table_open_on_id(table_id, false, DICT_TABLE_OP_NORMAL);
|
||||
|
||||
if (table == NULL) {
|
||||
/* Table is dropped. */
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!fil_table_accessible(table)) {
|
||||
release_fail:
|
||||
table->release();
|
||||
fail:
|
||||
if (mariadb_table) {
|
||||
close_thread_tables(thd);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!table_name_parse(table->name, db_buf1, tbl_buf1,
|
||||
db_buf1_len, tbl_buf1_len)) {
|
||||
goto release_fail;
|
||||
}
|
||||
|
||||
if (!mariadb_table) {
|
||||
} else if (!strcmp(db_buf, db_buf1) && !strcmp(tbl_buf, tbl_buf1)) {
|
||||
return mariadb_table;
|
||||
} else {
|
||||
if (table->vc_templ->mysql_table_query_id == thd_get_query_id(thd)) {
|
||||
/* Table is renamed. So release MDL for old name and try
|
||||
to acquire the MDL for new table name. */
|
||||
close_thread_tables(thd);
|
||||
}
|
||||
|
||||
strcpy(tbl_buf, tbl_buf1);
|
||||
strcpy(db_buf, db_buf1);
|
||||
tbl_buf_len = tbl_buf1_len;
|
||||
db_buf_len = db_buf1_len;
|
||||
goto retry_mdl;
|
||||
}
|
||||
|
||||
/** Find or open a table handle for the virtual column template
|
||||
@param[in] thd thread handle
|
||||
@param[in,out] table InnoDB table whose virtual column template
|
||||
is to be updated
|
||||
@return table handle
|
||||
@retval NULL if the table is dropped, unaccessible or corrupted
|
||||
for purge thread */
|
||||
static TABLE* innodb_find_table_for_vc(THD* thd, dict_table_t* table)
|
||||
{
|
||||
if (THDVAR(thd, background_thread)) {
|
||||
/* Purge thread acquires dict_operation_lock while
|
||||
processing undo log record. Release the dict_operation_lock
|
||||
before acquiring MDL on the table. */
|
||||
rw_lock_s_unlock(dict_operation_lock);
|
||||
return innodb_acquire_mdl(thd, table);
|
||||
} else {
|
||||
if (table->vc_templ->mysql_table_query_id
|
||||
== thd_get_query_id(thd)) {
|
||||
return table->vc_templ->mysql_table;
|
||||
}
|
||||
}
|
||||
|
||||
char dbname[MAX_DATABASE_NAME_LEN + 1];
|
||||
char tbname[MAX_TABLE_NAME_LEN + 1];
|
||||
char* name = table->name.m_name;
|
||||
uint dbnamelen = (uint) dict_get_db_name_len(name);
|
||||
uint tbnamelen = (uint) strlen(name) - dbnamelen - 1;
|
||||
char t_dbname[MAX_DATABASE_NAME_LEN + 1];
|
||||
char t_tbname[MAX_TABLE_NAME_LEN + 1];
|
||||
char db_buf[NAME_LEN + 1];
|
||||
char tbl_buf[NAME_LEN + 1];
|
||||
ulint db_buf_len, tbl_buf_len;
|
||||
|
||||
strncpy(dbname, name, dbnamelen);
|
||||
dbname[dbnamelen] = 0;
|
||||
strncpy(tbname, name + dbnamelen + 1, tbnamelen);
|
||||
tbname[tbnamelen] =0;
|
||||
|
||||
/* For partition table, remove the partition name and use the
|
||||
"main" table name to build the template */
|
||||
char* is_part = is_partition(tbname);
|
||||
|
||||
if (is_part != NULL) {
|
||||
*is_part = '\0';
|
||||
if (!table_name_parse(table->name, db_buf, tbl_buf,
|
||||
db_buf_len, tbl_buf_len)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dbnamelen = filename_to_tablename(dbname, t_dbname,
|
||||
MAX_DATABASE_NAME_LEN + 1);
|
||||
tbnamelen = filename_to_tablename(tbname, t_tbname,
|
||||
MAX_TABLE_NAME_LEN + 1);
|
||||
|
||||
if (bg_thread) {
|
||||
return open_purge_table(thd, t_dbname, dbnamelen,
|
||||
t_tbname, tbnamelen);
|
||||
}
|
||||
|
||||
mysql_table = find_fk_open_table(thd, t_dbname, dbnamelen,
|
||||
t_tbname, tbnamelen);
|
||||
TABLE* mysql_table = find_fk_open_table(thd, db_buf, db_buf_len,
|
||||
tbl_buf, tbl_buf_len);
|
||||
|
||||
table->vc_templ->mysql_table = mysql_table;
|
||||
table->vc_templ->mysql_table_query_id = thd_get_query_id(thd);
|
||||
@ -20693,7 +20781,7 @@ innobase_init_vc_templ(
|
||||
|
||||
table->vc_templ = UT_NEW_NOKEY(dict_vcol_templ_t());
|
||||
|
||||
TABLE *mysql_table= innobase_find_mysql_table_for_vc(current_thd, table);
|
||||
TABLE *mysql_table= innodb_find_table_for_vc(current_thd, table);
|
||||
|
||||
ut_ad(mysql_table);
|
||||
if (!mysql_table) {
|
||||
@ -20787,15 +20875,16 @@ innobase_get_field_from_update_vector(
|
||||
Allocate a heap and record for calculating virtual fields
|
||||
Used mainly for virtual fields in indexes
|
||||
|
||||
@param[in] thd MariaDB THD
|
||||
@param[in] index Index in use
|
||||
@param[in] thd MariaDB THD
|
||||
@param[in] index Index in use
|
||||
@param[out] heap Heap that holds temporary row
|
||||
@param[in,out] mysql_table MariaDB table
|
||||
@param[out] rec Pointer to allocated MariaDB record
|
||||
@param[out] storage Internal storage for blobs etc
|
||||
@param[in,out] table MariaDB table
|
||||
@param[out] record Pointer to allocated MariaDB record
|
||||
@param[out] storage Internal storage for blobs etc
|
||||
|
||||
@return FALSE ok
|
||||
@return TRUE malloc failure
|
||||
@retval false on success
|
||||
@retval true on malloc failure or failed to open the maria table
|
||||
for purge thread.
|
||||
*/
|
||||
|
||||
bool innobase_allocate_row_for_vcol(
|
||||
@ -20809,7 +20898,12 @@ bool innobase_allocate_row_for_vcol(
|
||||
TABLE *maria_table;
|
||||
String *blob_value_storage;
|
||||
if (!*table)
|
||||
*table= innobase_find_mysql_table_for_vc(thd, index->table);
|
||||
*table= innodb_find_table_for_vc(thd, index->table);
|
||||
|
||||
/* For purge thread, there is a possiblity that table could have
|
||||
dropped, corrupted or unaccessible. */
|
||||
if (!*table)
|
||||
return true;
|
||||
maria_table= *table;
|
||||
if (!*heap && !(*heap= mem_heap_create(srv_page_size)))
|
||||
{
|
||||
|
@ -121,7 +121,15 @@ enum btr_latch_mode {
|
||||
/** Attempt to purge a secondary index record
|
||||
while holding the dict_index_t::lock S-latch. */
|
||||
BTR_PURGE_LEAF_ALREADY_S_LATCHED = BTR_PURGE_LEAF
|
||||
| BTR_ALREADY_S_LATCHED
|
||||
| BTR_ALREADY_S_LATCHED,
|
||||
|
||||
/** In the case of BTR_MODIFY_TREE, the caller specifies
|
||||
the intention to delete record only. It is used to optimize
|
||||
block->lock range.*/
|
||||
BTR_LATCH_FOR_DELETE = 65536,
|
||||
|
||||
/** Attempt to purge a secondary index record in the tree. */
|
||||
BTR_PURGE_TREE = BTR_MODIFY_TREE | BTR_LATCH_FOR_DELETE
|
||||
};
|
||||
|
||||
/** This flag ORed to btr_latch_mode says that we do the search in query
|
||||
@ -137,10 +145,6 @@ the insert buffer to speed up inserts */
|
||||
to insert record only. It is used to optimize block->lock range.*/
|
||||
#define BTR_LATCH_FOR_INSERT 32768U
|
||||
|
||||
/** In the case of BTR_MODIFY_TREE, the caller specifies the intention
|
||||
to delete record only. It is used to optimize block->lock range.*/
|
||||
#define BTR_LATCH_FOR_DELETE 65536U
|
||||
|
||||
/** This flag is for undo insert of rtree. For rtree, we need this flag
|
||||
to find proper rec to undo insert.*/
|
||||
#define BTR_RTREE_UNDO_INS 131072U
|
||||
|
@ -301,6 +301,21 @@ btr_pcur_commit_specify_mtr(
|
||||
/*========================*/
|
||||
btr_pcur_t* pcur, /*!< in: persistent cursor */
|
||||
mtr_t* mtr); /*!< in: mtr to commit */
|
||||
|
||||
/** Commits the mtr and sets the clustered index pcur and secondary index
|
||||
pcur latch mode to BTR_NO_LATCHES, that is, the cursor becomes detached.
|
||||
Function btr_pcur_store_position should be used for both cursor before
|
||||
calling this, if restoration of cursor is wanted later.
|
||||
@param[in] pcur persistent cursor
|
||||
@param[in] sec_pcur secondary index persistent cursor
|
||||
@param[in] mtr mtr to commit */
|
||||
UNIV_INLINE
|
||||
void
|
||||
btr_pcurs_commit_specify_mtr(
|
||||
btr_pcur_t* pcur,
|
||||
btr_pcur_t* sec_pcur,
|
||||
mtr_t* mtr);
|
||||
|
||||
/*********************************************************//**
|
||||
Moves the persistent cursor to the next record in the tree. If no records are
|
||||
left, the cursor stays 'after last in tree'.
|
||||
|
@ -365,6 +365,32 @@ btr_pcur_commit_specify_mtr(
|
||||
pcur->pos_state = BTR_PCUR_WAS_POSITIONED;
|
||||
}
|
||||
|
||||
/** Commits the mtr and sets the clustered index pcur and secondary index
|
||||
pcur latch mode to BTR_NO_LATCHES, that is, the cursor becomes detached.
|
||||
Function btr_pcur_store_position should be used for both cursor before
|
||||
calling this, if restoration of cursor is wanted later.
|
||||
@param[in] pcur persistent cursor
|
||||
@param[in] sec_pcur secondary index persistent cursor
|
||||
@param[in] mtr mtr to commit */
|
||||
UNIV_INLINE
|
||||
void
|
||||
btr_pcurs_commit_specify_mtr(
|
||||
btr_pcur_t* pcur,
|
||||
btr_pcur_t* sec_pcur,
|
||||
mtr_t* mtr)
|
||||
{
|
||||
ut_ad(pcur->pos_state == BTR_PCUR_IS_POSITIONED);
|
||||
ut_ad(sec_pcur->pos_state == BTR_PCUR_IS_POSITIONED);
|
||||
|
||||
pcur->latch_mode = BTR_NO_LATCHES;
|
||||
sec_pcur->latch_mode = BTR_NO_LATCHES;
|
||||
|
||||
mtr_commit(mtr);
|
||||
|
||||
pcur->pos_state = BTR_PCUR_WAS_POSITIONED;
|
||||
sec_pcur->pos_state = BTR_PCUR_WAS_POSITIONED;
|
||||
}
|
||||
|
||||
/**************************************************************//**
|
||||
Sets the old_rec_buf field to NULL. */
|
||||
UNIV_INLINE
|
||||
|
@ -171,6 +171,9 @@ static inline bool btr_search_own_all(ulint mode);
|
||||
@retval true if owns any of them
|
||||
@retval false if owns no search latch */
|
||||
static inline bool btr_search_own_any(ulint mode);
|
||||
|
||||
/** @return whether this thread holds any of the search latches */
|
||||
static inline bool btr_search_own_any();
|
||||
#endif /* UNIV_DEBUG */
|
||||
|
||||
/** Unlock all search latches from shared mode. */
|
||||
|
@ -144,6 +144,18 @@ static inline bool btr_search_own_any(ulint mode)
|
||||
}
|
||||
return(false);
|
||||
}
|
||||
|
||||
/** @return whether this thread holds any of the search latches */
|
||||
static inline bool btr_search_own_any()
|
||||
{
|
||||
for (ulint i = btr_ahi_parts; i--; ) {
|
||||
if (rw_lock_own_flagged(btr_search_latches[i],
|
||||
RW_LOCK_FLAG_X | RW_LOCK_FLAG_S)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
#endif /* UNIV_DEBUG */
|
||||
|
||||
/** Get the adaptive hash search index latch for a b-tree.
|
||||
|
@ -1401,23 +1401,13 @@ dict_table_is_file_per_table(
|
||||
&& table->space != fil_system.temp_space;
|
||||
}
|
||||
|
||||
/** Get reference count.
|
||||
@return current value of n_ref_count */
|
||||
inline
|
||||
ulint
|
||||
dict_table_t::get_ref_count() const
|
||||
{
|
||||
ut_ad(mutex_own(&dict_sys->mutex));
|
||||
return(n_ref_count);
|
||||
}
|
||||
|
||||
/** Acquire the table handle. */
|
||||
inline
|
||||
void
|
||||
dict_table_t::acquire()
|
||||
{
|
||||
ut_ad(mutex_own(&dict_sys->mutex));
|
||||
++n_ref_count;
|
||||
my_atomic_add32_explicit(&n_ref_count, 1, MY_MEMORY_ORDER_RELAXED);
|
||||
}
|
||||
|
||||
/** Release the table handle.
|
||||
@ -1426,9 +1416,10 @@ inline
|
||||
bool
|
||||
dict_table_t::release()
|
||||
{
|
||||
ut_ad(mutex_own(&dict_sys->mutex));
|
||||
ut_ad(n_ref_count > 0);
|
||||
return !--n_ref_count;
|
||||
int32 n = my_atomic_add32_explicit(
|
||||
&n_ref_count, -1, MY_MEMORY_ORDER_RELAXED);
|
||||
ut_ad(n > 0);
|
||||
return n == 1;
|
||||
}
|
||||
|
||||
/** Encode the number of columns and number of virtual columns in a
|
||||
|
@ -1481,7 +1481,11 @@ struct dict_table_t {
|
||||
|
||||
/** Get reference count.
|
||||
@return current value of n_ref_count */
|
||||
inline ulint get_ref_count() const;
|
||||
inline int32 get_ref_count()
|
||||
{
|
||||
return my_atomic_load32_explicit(&n_ref_count,
|
||||
MY_MEMORY_ORDER_RELAXED);
|
||||
}
|
||||
|
||||
/** Acquire the table handle. */
|
||||
inline void acquire();
|
||||
@ -1928,13 +1932,11 @@ struct dict_table_t {
|
||||
It is protected by lock_sys.mutex. */
|
||||
ulint n_rec_locks;
|
||||
|
||||
#ifndef DBUG_ASSERT_EXISTS
|
||||
private:
|
||||
#endif
|
||||
/** Count of how many handles are opened to this table. Dropping of the
|
||||
table is NOT allowed until this count gets to zero. MySQL does NOT
|
||||
itself check the number of open handles at DROP. */
|
||||
ulint n_ref_count;
|
||||
int32 n_ref_count;
|
||||
|
||||
public:
|
||||
/** List of locks on the table. Protected by lock_sys.mutex. */
|
||||
|
@ -1,6 +1,7 @@
|
||||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 1994, 2015, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 2018, MariaDB Corporation.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free Software
|
||||
@ -137,11 +138,8 @@ hash_assert_can_search(
|
||||
if (table->type == HASH_TABLE_SYNC_MUTEX) {
|
||||
ut_ad(mutex_own(hash_get_mutex(table, fold)));
|
||||
} else if (table->type == HASH_TABLE_SYNC_RW_LOCK) {
|
||||
# ifdef UNIV_DEBUG
|
||||
rw_lock_t* lock = hash_get_lock(table, fold);
|
||||
ut_ad(rw_lock_own(lock, RW_LOCK_X)
|
||||
|| rw_lock_own(lock, RW_LOCK_S));
|
||||
# endif
|
||||
ut_ad(rw_lock_own_flagged(hash_get_lock(table, fold),
|
||||
RW_LOCK_FLAG_X | RW_LOCK_FLAG_S));
|
||||
} else {
|
||||
ut_ad(table->type == HASH_TABLE_SYNC_NONE);
|
||||
}
|
||||
|
@ -789,19 +789,21 @@ const lock_t*
|
||||
lock_trx_has_sys_table_locks(
|
||||
/*=========================*/
|
||||
const trx_t* trx) /*!< in: transaction to check */
|
||||
MY_ATTRIBUTE((warn_unused_result));
|
||||
MY_ATTRIBUTE((nonnull, warn_unused_result));
|
||||
|
||||
/*******************************************************************//**
|
||||
Check if the transaction holds an exclusive lock on a record.
|
||||
@return whether the locks are held */
|
||||
/** Check if the transaction holds an explicit exclusive lock on a record.
|
||||
@param[in] trx transaction
|
||||
@param[in] table table
|
||||
@param[in] block leaf page
|
||||
@param[in] heap_no heap number identifying the record
|
||||
@return whether an explicit X-lock is held */
|
||||
bool
|
||||
lock_trx_has_rec_x_lock(
|
||||
/*====================*/
|
||||
lock_trx_has_expl_x_lock(
|
||||
const trx_t* trx, /*!< in: transaction to check */
|
||||
const dict_table_t* table, /*!< in: table to check */
|
||||
const buf_block_t* block, /*!< in: buffer block of the record */
|
||||
ulint heap_no)/*!< in: record heap number */
|
||||
MY_ATTRIBUTE((warn_unused_result));
|
||||
MY_ATTRIBUTE((nonnull, warn_unused_result));
|
||||
#endif /* UNIV_DEBUG */
|
||||
|
||||
/**
|
||||
|
@ -36,6 +36,7 @@ Created 3/14/1997 Heikki Tuuri
|
||||
#include "que0types.h"
|
||||
#include "row0types.h"
|
||||
#include "ut0vec.h"
|
||||
#include "row0mysql.h"
|
||||
|
||||
/** Create a purge node to a query graph.
|
||||
@param[in] parent parent node, i.e., a thr node
|
||||
@ -47,8 +48,7 @@ row_purge_node_create(
|
||||
mem_heap_t* heap)
|
||||
MY_ATTRIBUTE((warn_unused_result));
|
||||
|
||||
/***********************************************************//**
|
||||
Determines if it is possible to remove a secondary index entry.
|
||||
/** Determines if it is possible to remove a secondary index entry.
|
||||
Removal is possible if the secondary index entry does not refer to any
|
||||
not delete marked version of a clustered index record where DB_TRX_ID
|
||||
is newer than the purge view.
|
||||
@ -61,14 +61,27 @@ inserts a record that the secondary index entry would refer to.
|
||||
However, in that case, the user transaction would also re-insert the
|
||||
secondary index entry after purge has removed it and released the leaf
|
||||
page latch.
|
||||
@param[in,out] node row purge node
|
||||
@param[in] index secondary index
|
||||
@param[in] entry secondary index entry
|
||||
@param[in,out] sec_pcur secondary index cursor or NULL
|
||||
if it is called for purge buffering
|
||||
operation.
|
||||
@param[in,out] sec_mtr mini-transaction which holds
|
||||
secondary index entry or NULL if it is
|
||||
called for purge buffering operation.
|
||||
@param[in] is_tree true=pessimistic purge,
|
||||
false=optimistic (leaf-page only)
|
||||
@return true if the secondary index record can be purged */
|
||||
bool
|
||||
row_purge_poss_sec(
|
||||
/*===============*/
|
||||
purge_node_t* node, /*!< in/out: row purge node */
|
||||
dict_index_t* index, /*!< in: secondary index */
|
||||
const dtuple_t* entry) /*!< in: secondary index entry */
|
||||
MY_ATTRIBUTE((nonnull, warn_unused_result));
|
||||
purge_node_t* node,
|
||||
dict_index_t* index,
|
||||
const dtuple_t* entry,
|
||||
btr_pcur_t* sec_pcur=NULL,
|
||||
mtr_t* sec_mtr=NULL,
|
||||
bool is_tree=false);
|
||||
|
||||
/***************************************************************
|
||||
Does the purge operation for a single undo log record. This is a high-level
|
||||
function used in an SQL execution graph.
|
||||
@ -117,6 +130,10 @@ struct purge_node_t{
|
||||
ibool done; /* Debug flag */
|
||||
trx_id_t trx_id; /*!< trx id for this purging record */
|
||||
|
||||
/** Virtual column information about opening of MariaDB table.
|
||||
It resets after processing each undo log record. */
|
||||
purge_vcol_info_t vcol_info;
|
||||
|
||||
#ifdef UNIV_DEBUG
|
||||
/***********************************************************//**
|
||||
Validate the persisent cursor. The purge node has two references
|
||||
@ -125,8 +142,13 @@ struct purge_node_t{
|
||||
each other if the found_clust flag is set.
|
||||
@return true if the persistent cursor is consistent with
|
||||
the ref member.*/
|
||||
bool validate_pcur();
|
||||
bool validate_pcur();
|
||||
#endif
|
||||
|
||||
/** Whether purge failed to open the maria table for virtual column
|
||||
computation.
|
||||
@return true if the table failed to open. */
|
||||
bool vcol_op_failed() const { return !vcol_info.validate(); }
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -1,6 +1,7 @@
|
||||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 1996, 2012, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 2018, MariaDB Corporation.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free Software
|
||||
@ -52,4 +53,93 @@ struct row_log_t;
|
||||
/* MySQL data types */
|
||||
struct TABLE;
|
||||
|
||||
/** Purge virtual column node information. */
|
||||
struct purge_vcol_info_t
|
||||
{
|
||||
private:
|
||||
/** Is there a possible need to evaluate virtual columns? */
|
||||
bool requested;
|
||||
/** Do we have to evaluate virtual columns (using mariadb_table)? */
|
||||
bool used;
|
||||
|
||||
/** True if it is used for the first time. */
|
||||
bool first_use;
|
||||
|
||||
/** MariaDB table opened for virtual column computation. */
|
||||
TABLE* mariadb_table;
|
||||
|
||||
public:
|
||||
/** Reset the state. */
|
||||
void reset()
|
||||
{
|
||||
requested = false;
|
||||
used = false;
|
||||
first_use = false;
|
||||
mariadb_table = NULL;
|
||||
}
|
||||
|
||||
/** Validate the virtual column information.
|
||||
@return true if the mariadb table opened successfully
|
||||
or doesn't try to calculate virtual column. */
|
||||
bool validate() const { return !used || mariadb_table; }
|
||||
|
||||
/** @return the table handle for evaluating virtual columns */
|
||||
TABLE* table() const { return mariadb_table; }
|
||||
|
||||
/** Set the table handle for evaluating virtual columns.
|
||||
@param[in] table table handle */
|
||||
void set_table(TABLE* table)
|
||||
{
|
||||
ut_ad(!table || is_first_fetch());
|
||||
mariadb_table = table;
|
||||
}
|
||||
|
||||
/** Note that virtual column information may be needed. */
|
||||
void set_requested()
|
||||
{
|
||||
ut_ad(!used);
|
||||
ut_ad(!first_use);
|
||||
ut_ad(!mariadb_table);
|
||||
requested = true;
|
||||
}
|
||||
|
||||
/** @return whether the virtual column information may be needed */
|
||||
bool is_requested() const { return requested; }
|
||||
|
||||
/** Note that the virtual column information is needed. */
|
||||
void set_used()
|
||||
{
|
||||
ut_ad(requested);
|
||||
|
||||
if (first_use) {
|
||||
first_use = false;
|
||||
ut_ad(used);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!used) {
|
||||
first_use = used = true;
|
||||
}
|
||||
}
|
||||
|
||||
/** @return whether the virtual column information is needed */
|
||||
bool is_used() const
|
||||
{
|
||||
ut_ad(!first_use || used);
|
||||
ut_ad(!used || requested);
|
||||
ut_ad(used || !mariadb_table);
|
||||
return used;
|
||||
}
|
||||
|
||||
/** Check whether it fetches mariadb table for the first time.
|
||||
@return true if first time tries to open mariadb table. */
|
||||
bool is_first_fetch() const
|
||||
{
|
||||
ut_ad(!first_use || used);
|
||||
ut_ad(!used || requested);
|
||||
ut_ad(used || !mariadb_table);
|
||||
return first_use;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -35,6 +35,7 @@ Created 2/6/1997 Heikki Tuuri
|
||||
#include "rem0types.h"
|
||||
#include "mtr0mtr.h"
|
||||
#include "dict0mem.h"
|
||||
#include "row0types.h"
|
||||
|
||||
// Forward declaration
|
||||
class ReadView;
|
||||
@ -54,27 +55,34 @@ row_vers_impl_x_locked(
|
||||
dict_index_t* index,
|
||||
const ulint* offsets);
|
||||
|
||||
/*****************************************************************//**
|
||||
Finds out if a version of the record, where the version >= the current
|
||||
/** Finds out if a version of the record, where the version >= the current
|
||||
purge view, should have ientry as its secondary index entry. We check
|
||||
if there is any not delete marked version of the record where the trx
|
||||
id >= purge view, and the secondary index entry == ientry; exactly in
|
||||
this case we return TRUE.
|
||||
@param[in] also_curr TRUE if also rec is included in the versions
|
||||
to search; otherwise only versions prior
|
||||
to it are searched
|
||||
@param[in] rec record in the clustered index; the caller
|
||||
must have a latch on the page
|
||||
@param[in] mtr mtr holding the latch on rec; it will
|
||||
also hold the latch on purge_view
|
||||
@param[in] index secondary index
|
||||
@param[in] ientry secondary index entry
|
||||
@param[in] roll_ptr roll_ptr for the purge record
|
||||
@param[in] trx_id transaction ID on the purging record
|
||||
@param[in,out] vcol_info virtual column information for purge thread.
|
||||
@return TRUE if earlier version should have */
|
||||
ibool
|
||||
bool
|
||||
row_vers_old_has_index_entry(
|
||||
/*=========================*/
|
||||
ibool also_curr,/*!< in: TRUE if also rec is included in the
|
||||
versions to search; otherwise only versions
|
||||
prior to it are searched */
|
||||
const rec_t* rec, /*!< in: record in the clustered index; the
|
||||
caller must have a latch on the page */
|
||||
mtr_t* mtr, /*!< in: mtr holding the latch on rec; it will
|
||||
also hold the latch on purge_view */
|
||||
dict_index_t* index, /*!< in: the secondary index */
|
||||
const dtuple_t* ientry, /*!< in: the secondary index entry */
|
||||
roll_ptr_t roll_ptr,/*!< in: roll_ptr for the purge record */
|
||||
trx_id_t trx_id);/*!< in: transaction ID on the purging record */
|
||||
bool also_curr,
|
||||
const rec_t* rec,
|
||||
mtr_t* mtr,
|
||||
dict_index_t* index,
|
||||
const dtuple_t* ientry,
|
||||
roll_ptr_t roll_ptr,
|
||||
trx_id_t trx_id,
|
||||
purge_vcol_info_t* vcol_info=NULL);
|
||||
|
||||
/*****************************************************************//**
|
||||
Constructs the version of a clustered index record which a consistent
|
||||
|
@ -279,8 +279,7 @@ rw_lock_s_lock_func(
|
||||
the threads which have s-locked a latch. This would use some CPU
|
||||
time. */
|
||||
|
||||
ut_ad(!rw_lock_own(lock, RW_LOCK_S)); /* see NOTE above */
|
||||
ut_ad(!rw_lock_own(lock, RW_LOCK_X));
|
||||
ut_ad(!rw_lock_own_flagged(lock, RW_LOCK_FLAG_X | RW_LOCK_FLAG_S));
|
||||
|
||||
if (!rw_lock_s_lock_low(lock, pass, file_name, line)) {
|
||||
|
||||
|
@ -979,8 +979,7 @@ struct latch_t {
|
||||
UNIV_NOTHROW
|
||||
:
|
||||
m_id(id),
|
||||
m_rw_lock(),
|
||||
m_temp_fsp() { }
|
||||
m_rw_lock() {}
|
||||
|
||||
/** Destructor */
|
||||
virtual ~latch_t() UNIV_NOTHROW { }
|
||||
@ -1014,24 +1013,6 @@ struct latch_t {
|
||||
return(sync_latch_get_level(m_id));
|
||||
}
|
||||
|
||||
/** @return true if the latch is for a temporary file space*/
|
||||
bool is_temp_fsp() const
|
||||
UNIV_NOTHROW
|
||||
{
|
||||
return(m_temp_fsp);
|
||||
}
|
||||
|
||||
/** Set the temporary tablespace flag. (For internal temporary
|
||||
tables, MySQL 5.7 does not always acquire the index->lock. We
|
||||
need to figure out the context and add some special rules
|
||||
during the checks.) */
|
||||
void set_temp_fsp()
|
||||
UNIV_NOTHROW
|
||||
{
|
||||
ut_ad(get_id() == LATCH_ID_FIL_SPACE);
|
||||
m_temp_fsp = true;
|
||||
}
|
||||
|
||||
/** @return the latch name, m_id must be set */
|
||||
const char* get_name() const
|
||||
UNIV_NOTHROW
|
||||
@ -1047,9 +1028,6 @@ struct latch_t {
|
||||
/** true if it is a rw-lock. In debug mode, rw_lock_t derives from
|
||||
this class and sets this variable. */
|
||||
bool m_rw_lock;
|
||||
|
||||
/** true if it is an temporary space latch */
|
||||
bool m_temp_fsp;
|
||||
};
|
||||
|
||||
/** Subclass this to iterate over a thread's acquired latch levels. */
|
||||
|
@ -616,7 +616,7 @@ public:
|
||||
@retval pointer to trx
|
||||
*/
|
||||
|
||||
trx_t *find(trx_t *caller_trx, trx_id_t trx_id, bool do_ref_count= false)
|
||||
trx_t *find(trx_t *caller_trx, trx_id_t trx_id, bool do_ref_count)
|
||||
{
|
||||
/*
|
||||
In MariaDB 10.3, purge will reset DB_TRX_ID to 0
|
||||
@ -624,9 +624,10 @@ public:
|
||||
always have a nonzero trx_t::id; there the value 0 is
|
||||
reserved for transactions that did not write or lock
|
||||
anything yet.
|
||||
|
||||
The caller should already have handled trx_id==0 specially.
|
||||
*/
|
||||
if (!trx_id)
|
||||
return NULL;
|
||||
ut_ad(trx_id);
|
||||
if (caller_trx && caller_trx->id == trx_id)
|
||||
{
|
||||
if (do_ref_count)
|
||||
@ -1044,13 +1045,13 @@ public:
|
||||
|
||||
bool is_registered(trx_t *caller_trx, trx_id_t id)
|
||||
{
|
||||
return rw_trx_hash.find(caller_trx, id);
|
||||
return id && find(caller_trx, id, false);
|
||||
}
|
||||
|
||||
|
||||
trx_t *find(trx_t *caller_trx, trx_id_t id)
|
||||
trx_t *find(trx_t *caller_trx, trx_id_t id, bool do_ref_count= true)
|
||||
{
|
||||
return rw_trx_hash.find(caller_trx, id, true);
|
||||
return rw_trx_hash.find(caller_trx, id, do_ref_count);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1433,7 +1433,7 @@ lock_rec_create_low(
|
||||
lock_rec_bitmap_reset(lock);
|
||||
lock_rec_set_nth_bit(lock, heap_no);
|
||||
index->table->n_rec_locks++;
|
||||
ut_ad(index->table->n_ref_count > 0 || !index->table->can_be_evicted);
|
||||
ut_ad(index->table->get_ref_count() > 0 || !index->table->can_be_evicted);
|
||||
|
||||
#ifdef WITH_WSREP
|
||||
if (c_lock && wsrep_on_trx(trx)
|
||||
@ -3531,7 +3531,7 @@ lock_table_create(
|
||||
|
||||
lock->un_member.tab_lock.table = table;
|
||||
|
||||
ut_ad(table->n_ref_count > 0 || !table->can_be_evicted);
|
||||
ut_ad(table->get_ref_count() > 0 || !table->can_be_evicted);
|
||||
|
||||
UT_LIST_ADD_LAST(trx->lock.trx_locks, lock);
|
||||
|
||||
@ -4937,8 +4937,12 @@ lock_rec_queue_validate(
|
||||
/* Unlike the non-debug code, this invariant can only succeed
|
||||
if the check and assertion are covered by the lock mutex. */
|
||||
|
||||
const trx_t *impl_trx = trx_sys.rw_trx_hash.find(current_trx(),
|
||||
lock_clust_rec_some_has_impl(rec, index, offsets));
|
||||
const trx_id_t impl_trx_id = lock_clust_rec_some_has_impl(
|
||||
rec, index, offsets);
|
||||
|
||||
const trx_t *impl_trx = impl_trx_id
|
||||
? trx_sys.find(current_trx(), impl_trx_id, false)
|
||||
: 0;
|
||||
|
||||
ut_ad(lock_mutex_own());
|
||||
/* impl_trx cannot be committed until lock_mutex_exit()
|
||||
@ -5547,18 +5551,31 @@ static void lock_rec_other_trx_holds_expl(trx_t *caller_trx, trx_t *trx,
|
||||
#endif /* UNIV_DEBUG */
|
||||
|
||||
|
||||
/*********************************************************************//**
|
||||
If a transaction has an implicit x-lock on a record, but no explicit x-lock
|
||||
set on the record, sets one for it. */
|
||||
/** If an implicit x-lock exists on a record, convert it to an explicit one.
|
||||
|
||||
Often, this is called by a transaction that is about to enter a lock wait
|
||||
due to the lock conflict. Two explicit locks would be created: first the
|
||||
exclusive lock on behalf of the lock-holder transaction in this function,
|
||||
and then a wait request on behalf of caller_trx, in the calling function.
|
||||
|
||||
This may also be called by the same transaction that is already holding
|
||||
an implicit exclusive lock on the record. In this case, no explicit lock
|
||||
should be created.
|
||||
|
||||
@param[in,out] caller_trx current transaction
|
||||
@param[in] block index tree leaf page
|
||||
@param[in] rec record on the leaf page
|
||||
@param[in] index the index of the record
|
||||
@param[in] offsets rec_get_offsets(rec,index)
|
||||
@return whether caller_trx already holds an exclusive lock on rec */
|
||||
static
|
||||
void
|
||||
bool
|
||||
lock_rec_convert_impl_to_expl(
|
||||
/*==========================*/
|
||||
trx_t* caller_trx,/*!<in/out: trx of current thread */
|
||||
const buf_block_t* block, /*!< in: buffer block of rec */
|
||||
const rec_t* rec, /*!< in: user record on page */
|
||||
dict_index_t* index, /*!< in: index of record */
|
||||
const ulint* offsets)/*!< in: rec_get_offsets(rec, index) */
|
||||
trx_t* caller_trx,
|
||||
const buf_block_t* block,
|
||||
const rec_t* rec,
|
||||
dict_index_t* index,
|
||||
const ulint* offsets)
|
||||
{
|
||||
trx_t* trx;
|
||||
|
||||
@ -5574,12 +5591,23 @@ lock_rec_convert_impl_to_expl(
|
||||
|
||||
trx_id = lock_clust_rec_some_has_impl(rec, index, offsets);
|
||||
|
||||
if (trx_id == 0) {
|
||||
return false;
|
||||
}
|
||||
if (UNIV_UNLIKELY(trx_id == caller_trx->id)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
trx = trx_sys.find(caller_trx, trx_id);
|
||||
} else {
|
||||
ut_ad(!dict_index_is_online_ddl(index));
|
||||
|
||||
trx = lock_sec_rec_some_has_impl(caller_trx, rec, index,
|
||||
offsets);
|
||||
if (trx == caller_trx) {
|
||||
trx->release_reference();
|
||||
return true;
|
||||
}
|
||||
|
||||
ut_d(lock_rec_other_trx_holds_expl(caller_trx, trx, rec,
|
||||
block));
|
||||
@ -5597,6 +5625,8 @@ lock_rec_convert_impl_to_expl(
|
||||
lock_rec_convert_impl_to_expl_for_trx(
|
||||
block, rec, index, trx, heap_no);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*********************************************************************//**
|
||||
@ -5641,8 +5671,11 @@ lock_clust_rec_modify_check_and_lock(
|
||||
/* If a transaction has no explicit x-lock set on the record, set one
|
||||
for it */
|
||||
|
||||
lock_rec_convert_impl_to_expl(thr_get_trx(thr), block, rec, index,
|
||||
offsets);
|
||||
if (lock_rec_convert_impl_to_expl(thr_get_trx(thr), block, rec, index,
|
||||
offsets)) {
|
||||
/* We already hold an implicit exclusive lock. */
|
||||
return DB_SUCCESS;
|
||||
}
|
||||
|
||||
err = lock_rec_lock(TRUE, LOCK_X | LOCK_REC_NOT_GAP,
|
||||
block, heap_no, index, thr);
|
||||
@ -5786,10 +5819,11 @@ lock_sec_rec_read_check_and_lock(
|
||||
database recovery is running. */
|
||||
|
||||
if (!page_rec_is_supremum(rec)
|
||||
&& page_get_max_trx_id(block->frame) >= trx_sys.get_min_trx_id()) {
|
||||
|
||||
lock_rec_convert_impl_to_expl(thr_get_trx(thr), block, rec,
|
||||
index, offsets);
|
||||
&& page_get_max_trx_id(block->frame) >= trx_sys.get_min_trx_id()
|
||||
&& lock_rec_convert_impl_to_expl(thr_get_trx(thr), block, rec,
|
||||
index, offsets)) {
|
||||
/* We already hold an implicit exclusive lock. */
|
||||
return DB_SUCCESS;
|
||||
}
|
||||
|
||||
err = lock_rec_lock(FALSE, ulint(mode) | gap_mode,
|
||||
@ -5850,10 +5884,11 @@ lock_clust_rec_read_check_and_lock(
|
||||
|
||||
heap_no = page_rec_get_heap_no(rec);
|
||||
|
||||
if (heap_no != PAGE_HEAP_NO_SUPREMUM) {
|
||||
|
||||
lock_rec_convert_impl_to_expl(thr_get_trx(thr), block, rec,
|
||||
index, offsets);
|
||||
if (heap_no != PAGE_HEAP_NO_SUPREMUM
|
||||
&& lock_rec_convert_impl_to_expl(thr_get_trx(thr), block, rec,
|
||||
index, offsets)) {
|
||||
/* We already hold an implicit exclusive lock. */
|
||||
return DB_SUCCESS;
|
||||
}
|
||||
|
||||
err = lock_rec_lock(FALSE, ulint(mode) | gap_mode,
|
||||
@ -6560,12 +6595,14 @@ lock_trx_has_sys_table_locks(
|
||||
return(strongest_lock);
|
||||
}
|
||||
|
||||
/*******************************************************************//**
|
||||
Check if the transaction holds an exclusive lock on a record.
|
||||
@return whether the locks are held */
|
||||
/** Check if the transaction holds an explicit exclusive lock on a record.
|
||||
@param[in] trx transaction
|
||||
@param[in] table table
|
||||
@param[in] block leaf page
|
||||
@param[in] heap_no heap number identifying the record
|
||||
@return whether an explicit X-lock is held */
|
||||
bool
|
||||
lock_trx_has_rec_x_lock(
|
||||
/*====================*/
|
||||
lock_trx_has_expl_x_lock(
|
||||
const trx_t* trx, /*!< in: transaction to check */
|
||||
const dict_table_t* table, /*!< in: table to check */
|
||||
const buf_block_t* block, /*!< in: buffer block of the record */
|
||||
@ -6574,11 +6611,9 @@ lock_trx_has_rec_x_lock(
|
||||
ut_ad(heap_no > PAGE_HEAP_NO_SUPREMUM);
|
||||
|
||||
lock_mutex_enter();
|
||||
ut_a(lock_table_has(trx, table, LOCK_IX)
|
||||
|| table->is_temporary());
|
||||
ut_a(lock_rec_has_expl(LOCK_X | LOCK_REC_NOT_GAP,
|
||||
block, heap_no, trx)
|
||||
|| table->is_temporary());
|
||||
ut_ad(lock_table_has(trx, table, LOCK_IX));
|
||||
ut_ad(lock_rec_has_expl(LOCK_X | LOCK_REC_NOT_GAP, block, heap_no,
|
||||
trx));
|
||||
lock_mutex_exit();
|
||||
return(true);
|
||||
}
|
||||
|
@ -4062,6 +4062,32 @@ next_file:
|
||||
return(status);
|
||||
}
|
||||
|
||||
/** Check that IO of specific size is possible for the file
|
||||
opened with FILE_FLAG_NO_BUFFERING.
|
||||
|
||||
The requirement is that IO is multiple of the disk sector size.
|
||||
|
||||
@param[in] file file handle
|
||||
@param[in] io_size expected io size
|
||||
@return true - unbuffered io of requested size is possible, false otherwise.
|
||||
|
||||
@note: this function only works correctly with Windows 8 or later,
|
||||
(GetFileInformationByHandleEx with FileStorageInfo is only supported there).
|
||||
It will return true on earlier Windows version.
|
||||
*/
|
||||
static bool unbuffered_io_possible(HANDLE file, size_t io_size)
|
||||
{
|
||||
FILE_STORAGE_INFO info;
|
||||
if (GetFileInformationByHandleEx(
|
||||
file, FileStorageInfo, &info, sizeof(info))) {
|
||||
ULONG sector_size = info.LogicalBytesPerSector;
|
||||
if (sector_size)
|
||||
return io_size % sector_size == 0;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/** NOTE! Use the corresponding macro os_file_create(), not directly
|
||||
this function!
|
||||
Opens an existing file or creates a new.
|
||||
@ -4237,46 +4263,58 @@ os_file_create_func(
|
||||
access |= GENERIC_WRITE;
|
||||
}
|
||||
|
||||
do {
|
||||
for (;;) {
|
||||
const char *operation;
|
||||
|
||||
/* Use default security attributes and no template file. */
|
||||
file = CreateFile(
|
||||
(LPCTSTR) name, access, share_mode, NULL,
|
||||
name, access, share_mode, NULL,
|
||||
create_flag, attributes, NULL);
|
||||
|
||||
if (file == INVALID_HANDLE_VALUE) {
|
||||
const char* operation;
|
||||
|
||||
operation = (create_mode == OS_FILE_CREATE
|
||||
&& !read_only)
|
||||
? "create" : "open";
|
||||
|
||||
*success = false;
|
||||
|
||||
if (on_error_no_exit) {
|
||||
retry = os_file_handle_error_no_exit(
|
||||
name, operation, on_error_silent);
|
||||
} else {
|
||||
retry = os_file_handle_error(name, operation);
|
||||
}
|
||||
} else {
|
||||
|
||||
retry = false;
|
||||
|
||||
*success = true;
|
||||
|
||||
if (srv_use_native_aio && ((attributes & FILE_FLAG_OVERLAPPED) != 0)) {
|
||||
/* Bind the file handle to completion port. Completion port
|
||||
might not be created yet, in some stages of backup, but
|
||||
must always be there for the server.*/
|
||||
HANDLE port =(type == OS_LOG_FILE)?
|
||||
log_completion_port : data_completion_port;
|
||||
ut_a(port || srv_operation != SRV_OPERATION_NORMAL);
|
||||
if (port) {
|
||||
ut_a(CreateIoCompletionPort(file, port, 0, 0));
|
||||
}
|
||||
}
|
||||
/* If FILE_FLAG_NO_BUFFERING was set, check if this can work at all,
|
||||
for expected IO sizes. Reopen without the unbuffered flag, if it is won't work*/
|
||||
if ((file != INVALID_HANDLE_VALUE)
|
||||
&& (attributes & FILE_FLAG_NO_BUFFERING)
|
||||
&& (type == OS_LOG_FILE)
|
||||
&& !unbuffered_io_possible(file, OS_FILE_LOG_BLOCK_SIZE)) {
|
||||
ut_a(CloseHandle(file));
|
||||
attributes &= ~FILE_FLAG_NO_BUFFERING;
|
||||
create_flag = OPEN_ALWAYS;
|
||||
continue;
|
||||
}
|
||||
} while (retry);
|
||||
|
||||
*success = (file != INVALID_HANDLE_VALUE);
|
||||
if (*success) {
|
||||
break;
|
||||
}
|
||||
|
||||
operation = (create_mode == OS_FILE_CREATE && !read_only) ?
|
||||
"create" : "open";
|
||||
|
||||
if (on_error_no_exit) {
|
||||
retry = os_file_handle_error_no_exit(
|
||||
name, operation, on_error_silent);
|
||||
}
|
||||
else {
|
||||
retry = os_file_handle_error(name, operation);
|
||||
}
|
||||
|
||||
if (!retry) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (*success && srv_use_native_aio && (attributes & FILE_FLAG_OVERLAPPED)) {
|
||||
/* Bind the file handle to completion port. Completion port
|
||||
might not be created yet, in some stages of backup, but
|
||||
must always be there for the server.*/
|
||||
HANDLE port = (type == OS_LOG_FILE) ?
|
||||
log_completion_port : data_completion_port;
|
||||
ut_a(port || srv_operation != SRV_OPERATION_NORMAL);
|
||||
if (port) {
|
||||
ut_a(CreateIoCompletionPort(file, port, 0, 0));
|
||||
}
|
||||
}
|
||||
|
||||
return(file);
|
||||
}
|
||||
|
@ -3863,7 +3863,7 @@ row_ins_step(
|
||||
/* No-rollback tables should only be written to by a
|
||||
single thread at a time, but there can be multiple
|
||||
concurrent readers. We must hold an open table handle. */
|
||||
DBUG_ASSERT(node->table->n_ref_count > 0);
|
||||
DBUG_ASSERT(node->table->get_ref_count() > 0);
|
||||
DBUG_ASSERT(node->ins_type == INS_DIRECT);
|
||||
/* No-rollback tables can consist only of a single index. */
|
||||
DBUG_ASSERT(UT_LIST_GET_LEN(node->entry_list) == 1);
|
||||
|
@ -329,8 +329,8 @@ row_log_online_op(
|
||||
|
||||
ut_ad(dtuple_validate(tuple));
|
||||
ut_ad(dtuple_get_n_fields(tuple) == dict_index_get_n_fields(index));
|
||||
ut_ad(rw_lock_own(dict_index_get_lock(index), RW_LOCK_S)
|
||||
|| rw_lock_own(dict_index_get_lock(index), RW_LOCK_X));
|
||||
ut_ad(rw_lock_own_flagged(&index->lock,
|
||||
RW_LOCK_FLAG_X | RW_LOCK_FLAG_S));
|
||||
|
||||
if (index->is_corrupted()) {
|
||||
return;
|
||||
|
@ -136,7 +136,8 @@ row_purge_remove_clust_if_poss_low(
|
||||
ulint offsets_[REC_OFFS_NORMAL_SIZE];
|
||||
rec_offs_init(offsets_);
|
||||
|
||||
ut_ad(rw_lock_own(dict_operation_lock, RW_LOCK_S));
|
||||
ut_ad(rw_lock_own(dict_operation_lock, RW_LOCK_S)
|
||||
|| node->vcol_info.is_used());
|
||||
|
||||
index = dict_table_get_first_index(node->table);
|
||||
|
||||
@ -230,8 +231,55 @@ row_purge_remove_clust_if_poss(
|
||||
return(false);
|
||||
}
|
||||
|
||||
/***********************************************************//**
|
||||
Determines if it is possible to remove a secondary index entry.
|
||||
/** Tries to store secondary index cursor before openin mysql table for
|
||||
virtual index condition computation.
|
||||
@param[in,out] node row purge node
|
||||
@param[in] index secondary index
|
||||
@param[in,out] sec_pcur secondary index cursor
|
||||
@param[in,out] sec_mtr mini-transaction which holds
|
||||
secondary index entry */
|
||||
static void row_purge_store_vsec_cur(
|
||||
purge_node_t* node,
|
||||
dict_index_t* index,
|
||||
btr_pcur_t* sec_pcur,
|
||||
mtr_t* sec_mtr)
|
||||
{
|
||||
row_purge_reposition_pcur(BTR_SEARCH_LEAF, node, sec_mtr);
|
||||
|
||||
if (!node->found_clust) {
|
||||
return;
|
||||
}
|
||||
|
||||
node->vcol_info.set_requested();
|
||||
|
||||
btr_pcur_store_position(sec_pcur, sec_mtr);
|
||||
|
||||
btr_pcurs_commit_specify_mtr(&node->pcur, sec_pcur, sec_mtr);
|
||||
}
|
||||
|
||||
/** Tries to restore secondary index cursor after opening the mysql table
|
||||
@param[in,out] node row purge node
|
||||
@param[in] index secondary index
|
||||
@param[in,out] sec_mtr mini-transaction which holds secondary index entry
|
||||
@param[in] is_tree true=pessimistic purge,
|
||||
false=optimistic (leaf-page only)
|
||||
@return false in case of restore failure. */
|
||||
static bool row_purge_restore_vsec_cur(
|
||||
purge_node_t* node,
|
||||
dict_index_t* index,
|
||||
btr_pcur_t* sec_pcur,
|
||||
mtr_t* sec_mtr,
|
||||
bool is_tree)
|
||||
{
|
||||
sec_mtr->start();
|
||||
index->set_modified(*sec_mtr);
|
||||
|
||||
return btr_pcur_restore_position(
|
||||
is_tree ? BTR_PURGE_TREE : BTR_PURGE_LEAF,
|
||||
sec_pcur, sec_mtr);
|
||||
}
|
||||
|
||||
/** Determines if it is possible to remove a secondary index entry.
|
||||
Removal is possible if the secondary index entry does not refer to any
|
||||
not delete marked version of a clustered index record where DB_TRX_ID
|
||||
is newer than the purge view.
|
||||
@ -244,34 +292,95 @@ inserts a record that the secondary index entry would refer to.
|
||||
However, in that case, the user transaction would also re-insert the
|
||||
secondary index entry after purge has removed it and released the leaf
|
||||
page latch.
|
||||
@param[in,out] node row purge node
|
||||
@param[in] index secondary index
|
||||
@param[in] entry secondary index entry
|
||||
@param[in,out] sec_pcur secondary index cursor or NULL
|
||||
if it is called for purge buffering
|
||||
operation.
|
||||
@param[in,out] sec_mtr mini-transaction which holds
|
||||
secondary index entry or NULL if it is
|
||||
called for purge buffering operation.
|
||||
@param[in] is_tree true=pessimistic purge,
|
||||
false=optimistic (leaf-page only)
|
||||
@return true if the secondary index record can be purged */
|
||||
bool
|
||||
row_purge_poss_sec(
|
||||
/*===============*/
|
||||
purge_node_t* node, /*!< in/out: row purge node */
|
||||
dict_index_t* index, /*!< in: secondary index */
|
||||
const dtuple_t* entry) /*!< in: secondary index entry */
|
||||
purge_node_t* node,
|
||||
dict_index_t* index,
|
||||
const dtuple_t* entry,
|
||||
btr_pcur_t* sec_pcur,
|
||||
mtr_t* sec_mtr,
|
||||
bool is_tree)
|
||||
{
|
||||
bool can_delete;
|
||||
mtr_t mtr;
|
||||
|
||||
ut_ad(!dict_index_is_clust(index));
|
||||
|
||||
const bool store_cur = sec_mtr && !node->vcol_info.is_used()
|
||||
&& dict_index_has_virtual(index);
|
||||
|
||||
if (store_cur) {
|
||||
row_purge_store_vsec_cur(node, index, sec_pcur, sec_mtr);
|
||||
ut_ad(sec_mtr->has_committed()
|
||||
== node->vcol_info.is_requested());
|
||||
|
||||
/* The PRIMARY KEY value was not found in the clustered
|
||||
index. The secondary index record found. We can purge
|
||||
the secondary index record. */
|
||||
if (!node->vcol_info.is_requested()) {
|
||||
ut_ad(!node->found_clust);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
retry_purge_sec:
|
||||
mtr_start(&mtr);
|
||||
|
||||
can_delete = !row_purge_reposition_pcur(BTR_SEARCH_LEAF, node, &mtr)
|
||||
|| !row_vers_old_has_index_entry(TRUE,
|
||||
|| !row_vers_old_has_index_entry(true,
|
||||
btr_pcur_get_rec(&node->pcur),
|
||||
&mtr, index, entry,
|
||||
node->roll_ptr, node->trx_id);
|
||||
node->roll_ptr, node->trx_id,
|
||||
&node->vcol_info);
|
||||
|
||||
if (node->vcol_info.is_first_fetch()) {
|
||||
ut_ad(store_cur);
|
||||
|
||||
const TABLE* t= node->vcol_info.table();
|
||||
DBUG_LOG("purge", "retry " << t
|
||||
<< (is_tree ? " tree" : " leaf")
|
||||
<< index->name << "," << index->table->name
|
||||
<< ": " << rec_printer(entry).str());
|
||||
|
||||
ut_ad(mtr.has_committed());
|
||||
|
||||
if (t) {
|
||||
node->vcol_info.set_used();
|
||||
goto retry_purge_sec;
|
||||
}
|
||||
|
||||
node->table = NULL;
|
||||
sec_pcur = NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Persistent cursor is closed if reposition fails. */
|
||||
if (node->found_clust) {
|
||||
btr_pcur_commit_specify_mtr(&node->pcur, &mtr);
|
||||
} else {
|
||||
mtr_commit(&mtr);
|
||||
mtr.commit();
|
||||
}
|
||||
|
||||
return(can_delete);
|
||||
ut_ad(mtr.has_committed());
|
||||
|
||||
if (store_cur && !row_purge_restore_vsec_cur(
|
||||
node, index, sec_pcur, sec_mtr, is_tree)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return can_delete;
|
||||
}
|
||||
|
||||
/***************************************************************
|
||||
@ -287,7 +396,6 @@ row_purge_remove_sec_if_poss_tree(
|
||||
const dtuple_t* entry) /*!< in: index entry */
|
||||
{
|
||||
btr_pcur_t pcur;
|
||||
btr_cur_t* btr_cur;
|
||||
ibool success = TRUE;
|
||||
dberr_t err;
|
||||
mtr_t mtr;
|
||||
@ -348,16 +456,16 @@ row_purge_remove_sec_if_poss_tree(
|
||||
ut_error;
|
||||
}
|
||||
|
||||
btr_cur = btr_pcur_get_btr_cur(&pcur);
|
||||
|
||||
/* We should remove the index record if no later version of the row,
|
||||
which cannot be purged yet, requires its existence. If some requires,
|
||||
we should do nothing. */
|
||||
|
||||
if (row_purge_poss_sec(node, index, entry)) {
|
||||
if (row_purge_poss_sec(node, index, entry, &pcur, &mtr, true)) {
|
||||
|
||||
/* Remove the index record, which should have been
|
||||
marked for deletion. */
|
||||
if (!rec_get_deleted_flag(btr_cur_get_rec(btr_cur),
|
||||
if (!rec_get_deleted_flag(btr_cur_get_rec(
|
||||
btr_pcur_get_btr_cur(&pcur)),
|
||||
dict_table_is_comp(index->table))) {
|
||||
ib::error()
|
||||
<< "tried to purge non-delete-marked record"
|
||||
@ -365,15 +473,18 @@ row_purge_remove_sec_if_poss_tree(
|
||||
<< " of table " << index->table->name
|
||||
<< ": tuple: " << *entry
|
||||
<< ", record: " << rec_index_print(
|
||||
btr_cur_get_rec(btr_cur), index);
|
||||
btr_cur_get_rec(
|
||||
btr_pcur_get_btr_cur(&pcur)),
|
||||
index);
|
||||
|
||||
ut_ad(0);
|
||||
|
||||
goto func_exit;
|
||||
}
|
||||
|
||||
btr_cur_pessimistic_delete(&err, FALSE, btr_cur, 0,
|
||||
false, &mtr);
|
||||
btr_cur_pessimistic_delete(&err, FALSE,
|
||||
btr_pcur_get_btr_cur(&pcur),
|
||||
0, false, &mtr);
|
||||
switch (UNIV_EXPECT(err, DB_SUCCESS)) {
|
||||
case DB_SUCCESS:
|
||||
break;
|
||||
@ -385,6 +496,13 @@ row_purge_remove_sec_if_poss_tree(
|
||||
}
|
||||
}
|
||||
|
||||
if (node->vcol_op_failed()) {
|
||||
ut_ad(mtr.has_committed());
|
||||
ut_ad(!pcur.old_rec_buf);
|
||||
ut_ad(pcur.pos_state == BTR_PCUR_NOT_POSITIONED);
|
||||
return false;
|
||||
}
|
||||
|
||||
func_exit:
|
||||
btr_pcur_close(&pcur);
|
||||
func_exit_no_pcur:
|
||||
@ -445,8 +563,10 @@ row_purge_remove_sec_if_poss_leaf(
|
||||
index->is_committed(). */
|
||||
ut_ad(!dict_index_is_online_ddl(index));
|
||||
|
||||
/* Change buffering is disabled for spatial index. */
|
||||
mode = dict_index_is_spatial(index)
|
||||
/* Change buffering is disabled for spatial index and
|
||||
virtual index. */
|
||||
mode = (dict_index_is_spatial(index)
|
||||
|| dict_index_has_virtual(index))
|
||||
? BTR_MODIFY_LEAF
|
||||
: BTR_PURGE_LEAF;
|
||||
}
|
||||
@ -474,7 +594,7 @@ row_purge_remove_sec_if_poss_leaf(
|
||||
case ROW_FOUND:
|
||||
/* Before attempting to purge a record, check
|
||||
if it is safe to do so. */
|
||||
if (row_purge_poss_sec(node, index, entry)) {
|
||||
if (row_purge_poss_sec(node, index, entry, &pcur, &mtr, false)) {
|
||||
btr_cur_t* btr_cur = btr_pcur_get_btr_cur(&pcur);
|
||||
|
||||
/* Only delete-marked records should be purged. */
|
||||
@ -540,6 +660,12 @@ row_purge_remove_sec_if_poss_leaf(
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (node->vcol_op_failed()) {
|
||||
btr_pcur_close(&pcur);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* (The index entry is still needed,
|
||||
or the deletion succeeded) */
|
||||
/* fall through */
|
||||
@ -586,6 +712,10 @@ row_purge_remove_sec_if_poss(
|
||||
return;
|
||||
}
|
||||
retry:
|
||||
if (node->vcol_op_failed()) {
|
||||
return;
|
||||
}
|
||||
|
||||
success = row_purge_remove_sec_if_poss_tree(node, index, entry);
|
||||
/* The delete operation may fail if we have little
|
||||
file space left: TODO: easiest to crash the database
|
||||
@ -652,6 +782,12 @@ row_purge_del_mark(
|
||||
node->row, NULL, node->index,
|
||||
heap, ROW_BUILD_FOR_PURGE);
|
||||
row_purge_remove_sec_if_poss(node, node->index, entry);
|
||||
|
||||
if (node->vcol_op_failed()) {
|
||||
mem_heap_free(heap);
|
||||
return false;
|
||||
}
|
||||
|
||||
mem_heap_empty(heap);
|
||||
}
|
||||
|
||||
@ -667,11 +803,10 @@ row_purge_del_mark(
|
||||
whose old history can no longer be observed.
|
||||
@param[in,out] node purge node
|
||||
@param[in,out] mtr mini-transaction (will be started and committed) */
|
||||
static
|
||||
void
|
||||
row_purge_reset_trx_id(purge_node_t* node, mtr_t* mtr)
|
||||
static void row_purge_reset_trx_id(purge_node_t* node, mtr_t* mtr)
|
||||
{
|
||||
ut_ad(rw_lock_own(dict_operation_lock, RW_LOCK_S));
|
||||
ut_ad(rw_lock_own(dict_operation_lock, RW_LOCK_S)
|
||||
|| node->vcol_info.is_used());
|
||||
/* Reset DB_TRX_ID, DB_ROLL_PTR for old records. */
|
||||
mtr->start();
|
||||
|
||||
@ -746,7 +881,8 @@ row_purge_upd_exist_or_extern_func(
|
||||
{
|
||||
mem_heap_t* heap;
|
||||
|
||||
ut_ad(rw_lock_own(dict_operation_lock, RW_LOCK_S));
|
||||
ut_ad(rw_lock_own(dict_operation_lock, RW_LOCK_S)
|
||||
|| node->vcol_info.is_used());
|
||||
ut_ad(!node->table->skip_alter_undo);
|
||||
|
||||
if (node->rec_type == TRX_UNDO_UPD_DEL_REC
|
||||
@ -1107,10 +1243,15 @@ row_purge(
|
||||
bool purged = row_purge_record(
|
||||
node, undo_rec, thr, updated_extern);
|
||||
|
||||
rw_lock_s_unlock(dict_operation_lock);
|
||||
if (!node->vcol_info.is_used()) {
|
||||
rw_lock_s_unlock(dict_operation_lock);
|
||||
}
|
||||
|
||||
ut_ad(!rw_lock_own(dict_operation_lock, RW_LOCK_S));
|
||||
|
||||
if (purged
|
||||
|| srv_shutdown_state != SRV_SHUTDOWN_NONE) {
|
||||
|| srv_shutdown_state != SRV_SHUTDOWN_NONE
|
||||
|| node->vcol_op_failed()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1142,6 +1283,8 @@ row_purge_end(
|
||||
|
||||
node->done = TRUE;
|
||||
|
||||
node->vcol_info.reset();
|
||||
|
||||
ut_a(thr->run_node != NULL);
|
||||
|
||||
mem_heap_empty(node->heap);
|
||||
@ -1189,6 +1332,7 @@ row_purge_step(
|
||||
row_purge_end(thr);
|
||||
} else {
|
||||
thr->run_node = node;
|
||||
node->vcol_info.reset();
|
||||
}
|
||||
} else {
|
||||
row_purge_end(thr);
|
||||
|
@ -1100,8 +1100,8 @@ sel_set_rtr_rec_lock(
|
||||
rw_lock_x_lock(&(match->block.lock));
|
||||
retry:
|
||||
cur_block = btr_pcur_get_block(pcur);
|
||||
ut_ad(rw_lock_own(&(match->block.lock), RW_LOCK_X)
|
||||
|| rw_lock_own(&(match->block.lock), RW_LOCK_S));
|
||||
ut_ad(rw_lock_own_flagged(&match->block.lock,
|
||||
RW_LOCK_FLAG_X | RW_LOCK_FLAG_S));
|
||||
ut_ad(page_is_leaf(buf_block_get_frame(cur_block)));
|
||||
|
||||
err = lock_sec_rec_read_check_and_lock(
|
||||
|
@ -1757,6 +1757,8 @@ row_truncate_table_for_mysql(
|
||||
trx_set_dict_operation(trx, TRX_DICT_OP_TABLE);
|
||||
}
|
||||
|
||||
DEBUG_SYNC_C("row_trunc_before_dict_lock");
|
||||
|
||||
/* Step-3: Validate ownership of needed locks (Exclusive lock).
|
||||
Ownership will also ensure there is no active SQL queries, INSERT,
|
||||
SELECT, .....*/
|
||||
|
@ -222,8 +222,8 @@ row_undo_mod_clust(
|
||||
ut_ad(thr_get_trx(thr) == node->trx);
|
||||
ut_ad(node->trx->dict_operation_lock_mode);
|
||||
ut_ad(node->trx->in_rollback);
|
||||
ut_ad(rw_lock_own(dict_operation_lock, RW_LOCK_S)
|
||||
|| rw_lock_own(dict_operation_lock, RW_LOCK_X));
|
||||
ut_ad(rw_lock_own_flagged(dict_operation_lock,
|
||||
RW_LOCK_FLAG_X | RW_LOCK_FLAG_S));
|
||||
|
||||
log_free_check();
|
||||
pcur = &node->pcur;
|
||||
@ -543,7 +543,7 @@ row_undo_mod_del_mark_or_remove_sec_low(
|
||||
clustered index entry, because there is no MVCC or purge. */
|
||||
if (node->table->is_temporary()
|
||||
|| row_vers_old_has_index_entry(
|
||||
FALSE, btr_pcur_get_rec(&node->pcur),
|
||||
false, btr_pcur_get_rec(&node->pcur),
|
||||
&mtr_vers, index, entry, 0, 0)) {
|
||||
err = btr_cur_del_mark_set_sec_rec(BTR_NO_LOCKING_FLAG,
|
||||
btr_cur, TRUE, thr, &mtr);
|
||||
|
@ -3093,9 +3093,7 @@ row_upd_clust_step(
|
||||
|
||||
ulint mode;
|
||||
|
||||
DEBUG_SYNC_C_IF_THD(
|
||||
thr_get_trx(thr)->mysql_thd,
|
||||
"innodb_row_upd_clust_step_enter");
|
||||
DEBUG_SYNC_C_IF_THD(trx->mysql_thd, "innodb_row_upd_clust_step_enter");
|
||||
|
||||
if (dict_index_is_online_ddl(index)) {
|
||||
ut_ad(node->table->id != DICT_INDEXES_ID);
|
||||
@ -3157,10 +3155,11 @@ row_upd_clust_step(
|
||||
}
|
||||
}
|
||||
|
||||
ut_ad(index->table->no_rollback()
|
||||
|| lock_trx_has_rec_x_lock(thr_get_trx(thr), index->table,
|
||||
btr_pcur_get_block(pcur),
|
||||
page_rec_get_heap_no(rec)));
|
||||
ut_ad(index->table->no_rollback() || index->table->is_temporary()
|
||||
|| row_get_rec_trx_id(rec, index, offsets) == trx->id
|
||||
|| lock_trx_has_expl_x_lock(trx, index->table,
|
||||
btr_pcur_get_block(pcur),
|
||||
page_rec_get_heap_no(rec)));
|
||||
|
||||
/* NOTE: the following function calls will also commit mtr */
|
||||
|
||||
|
@ -126,14 +126,22 @@ row_vers_impl_x_locked_low(
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
trx_t* trx = trx_sys.find(caller_trx, trx_id);
|
||||
trx_t* trx;
|
||||
|
||||
if (trx == 0) {
|
||||
/* The transaction that modified or inserted clust_rec is no
|
||||
longer active, or it is corrupt: no implicit lock on rec */
|
||||
lock_check_trx_id_sanity(trx_id, clust_rec, clust_index, clust_offsets);
|
||||
mem_heap_free(heap);
|
||||
DBUG_RETURN(0);
|
||||
if (trx_id == caller_trx->id) {
|
||||
trx = caller_trx;
|
||||
trx->reference();
|
||||
} else {
|
||||
trx = trx_sys.find(caller_trx, trx_id);
|
||||
if (trx == 0) {
|
||||
/* The transaction that modified or inserted
|
||||
clust_rec is no longer active, or it is
|
||||
corrupt: no implicit lock on rec */
|
||||
lock_check_trx_id_sanity(trx_id, clust_rec,
|
||||
clust_index, clust_offsets);
|
||||
mem_heap_free(heap);
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
}
|
||||
|
||||
comp = page_rec_is_comp(rec);
|
||||
@ -424,14 +432,16 @@ row_vers_impl_x_locked(
|
||||
@param[in,out] row the cluster index row in dtuple form
|
||||
@param[in] clust_index clustered index
|
||||
@param[in] index the secondary index
|
||||
@param[in] heap heap used to build virtual dtuple */
|
||||
@param[in] heap heap used to build virtual dtuple
|
||||
@param[in,out] vcol_info virtual column information. */
|
||||
static
|
||||
void
|
||||
row_vers_build_clust_v_col(
|
||||
dtuple_t* row,
|
||||
dict_index_t* clust_index,
|
||||
dict_index_t* index,
|
||||
mem_heap_t* heap)
|
||||
dtuple_t* row,
|
||||
dict_index_t* clust_index,
|
||||
dict_index_t* index,
|
||||
mem_heap_t* heap,
|
||||
purge_vcol_info_t* vcol_info)
|
||||
{
|
||||
mem_heap_t* local_heap = NULL;
|
||||
VCOL_STORAGE *vcol_storage= NULL;
|
||||
@ -441,12 +451,22 @@ row_vers_build_clust_v_col(
|
||||
|
||||
ut_ad(dict_index_has_virtual(index));
|
||||
|
||||
if (vcol_info != NULL) {
|
||||
vcol_info->set_used();
|
||||
maria_table = vcol_info->table();
|
||||
}
|
||||
|
||||
innobase_allocate_row_for_vcol(thd, index,
|
||||
&local_heap,
|
||||
&maria_table,
|
||||
&record,
|
||||
&vcol_storage);
|
||||
|
||||
if (vcol_info && !vcol_info->table()) {
|
||||
vcol_info->set_table(maria_table);
|
||||
goto func_exit;
|
||||
}
|
||||
|
||||
for (ulint i = 0; i < dict_index_get_n_fields(index); i++) {
|
||||
const dict_field_t* ind_field = dict_index_get_nth_field(
|
||||
index, i);
|
||||
@ -464,6 +484,7 @@ row_vers_build_clust_v_col(
|
||||
}
|
||||
}
|
||||
|
||||
func_exit:
|
||||
if (local_heap) {
|
||||
if (vcol_storage)
|
||||
innobase_free_row_for_vcol(vcol_storage);
|
||||
@ -485,16 +506,16 @@ row_vers_build_clust_v_col(
|
||||
static
|
||||
void
|
||||
row_vers_build_cur_vrow_low(
|
||||
bool in_purge,
|
||||
const rec_t* rec,
|
||||
dict_index_t* clust_index,
|
||||
ulint* clust_offsets,
|
||||
dict_index_t* index,
|
||||
roll_ptr_t roll_ptr,
|
||||
trx_id_t trx_id,
|
||||
mem_heap_t* v_heap,
|
||||
const dtuple_t**vrow,
|
||||
mtr_t* mtr)
|
||||
bool in_purge,
|
||||
const rec_t* rec,
|
||||
dict_index_t* clust_index,
|
||||
ulint* clust_offsets,
|
||||
dict_index_t* index,
|
||||
roll_ptr_t roll_ptr,
|
||||
trx_id_t trx_id,
|
||||
mem_heap_t* v_heap,
|
||||
const dtuple_t** vrow,
|
||||
mtr_t* mtr)
|
||||
{
|
||||
const rec_t* version;
|
||||
rec_t* prev_version;
|
||||
@ -771,20 +792,22 @@ func_exit:
|
||||
@param[in,out] heap heap memory
|
||||
@param[in,out] v_heap heap memory to keep virtual colum dtuple
|
||||
@param[in] mtr mtr holding the latch on rec
|
||||
@param[in,out] vcol_info virtual column information for purge thread
|
||||
@return dtuple contains virtual column data */
|
||||
static
|
||||
const dtuple_t*
|
||||
row_vers_build_cur_vrow(
|
||||
bool in_purge,
|
||||
const rec_t* rec,
|
||||
dict_index_t* clust_index,
|
||||
ulint** clust_offsets,
|
||||
dict_index_t* index,
|
||||
roll_ptr_t roll_ptr,
|
||||
trx_id_t trx_id,
|
||||
mem_heap_t* heap,
|
||||
mem_heap_t* v_heap,
|
||||
mtr_t* mtr)
|
||||
bool in_purge,
|
||||
const rec_t* rec,
|
||||
dict_index_t* clust_index,
|
||||
ulint** clust_offsets,
|
||||
dict_index_t* index,
|
||||
roll_ptr_t roll_ptr,
|
||||
trx_id_t trx_id,
|
||||
mem_heap_t* heap,
|
||||
mem_heap_t* v_heap,
|
||||
mtr_t* mtr,
|
||||
purge_vcol_info_t* vcol_info)
|
||||
{
|
||||
const dtuple_t* cur_vrow = NULL;
|
||||
|
||||
@ -804,8 +827,17 @@ row_vers_build_cur_vrow(
|
||||
rec, *clust_offsets,
|
||||
NULL, NULL, NULL, NULL, heap);
|
||||
|
||||
if (vcol_info && !vcol_info->is_used()) {
|
||||
mtr->commit();
|
||||
}
|
||||
|
||||
row_vers_build_clust_v_col(
|
||||
row, clust_index, index, heap);
|
||||
row, clust_index, index, heap, vcol_info);
|
||||
|
||||
if (vcol_info != NULL && vcol_info->is_first_fetch()) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cur_vrow = dtuple_copy(row, v_heap);
|
||||
dtuple_dup_v_fld(cur_vrow, v_heap);
|
||||
} else {
|
||||
@ -820,27 +852,34 @@ row_vers_build_cur_vrow(
|
||||
return(cur_vrow);
|
||||
}
|
||||
|
||||
/*****************************************************************//**
|
||||
Finds out if a version of the record, where the version >= the current
|
||||
/** Finds out if a version of the record, where the version >= the current
|
||||
purge view, should have ientry as its secondary index entry. We check
|
||||
if there is any not delete marked version of the record where the trx
|
||||
id >= purge view, and the secondary index entry and ientry are identified in
|
||||
the alphabetical ordering; exactly in this case we return TRUE.
|
||||
id >= purge view, and the secondary index entry == ientry; exactly in
|
||||
this case we return TRUE.
|
||||
@param[in] also_curr TRUE if also rec is included in the versions
|
||||
to search; otherwise only versions prior
|
||||
to it are searched
|
||||
@param[in] rec record in the clustered index; the caller
|
||||
must have a latch on the page
|
||||
@param[in] mtr mtr holding the latch on rec; it will
|
||||
also hold the latch on purge_view
|
||||
@param[in] index secondary index
|
||||
@param[in] ientry secondary index entry
|
||||
@param[in] roll_ptr roll_ptr for the purge record
|
||||
@param[in] trx_id transaction ID on the purging record
|
||||
@param[in,out] vcol_info virtual column information for purge thread.
|
||||
@return TRUE if earlier version should have */
|
||||
ibool
|
||||
bool
|
||||
row_vers_old_has_index_entry(
|
||||
/*=========================*/
|
||||
ibool also_curr,/*!< in: TRUE if also rec is included in the
|
||||
versions to search; otherwise only versions
|
||||
prior to it are searched */
|
||||
const rec_t* rec, /*!< in: record in the clustered index; the
|
||||
caller must have a latch on the page */
|
||||
mtr_t* mtr, /*!< in: mtr holding the latch on rec; it will
|
||||
also hold the latch on purge_view */
|
||||
dict_index_t* index, /*!< in: the secondary index */
|
||||
const dtuple_t* ientry, /*!< in: the secondary index entry */
|
||||
roll_ptr_t roll_ptr,/*!< in: roll_ptr for the purge record */
|
||||
trx_id_t trx_id) /*!< in: transaction ID on the purging record */
|
||||
bool also_curr,
|
||||
const rec_t* rec,
|
||||
mtr_t* mtr,
|
||||
dict_index_t* index,
|
||||
const dtuple_t* ientry,
|
||||
roll_ptr_t roll_ptr,
|
||||
trx_id_t trx_id,
|
||||
purge_vcol_info_t* vcol_info)
|
||||
{
|
||||
const rec_t* version;
|
||||
rec_t* prev_version;
|
||||
@ -908,8 +947,18 @@ row_vers_old_has_index_entry(
|
||||
columns need to be computed */
|
||||
if (trx_undo_roll_ptr_is_insert(t_roll_ptr)
|
||||
|| dbug_v_purge) {
|
||||
|
||||
if (vcol_info && !vcol_info->is_used()) {
|
||||
mtr->commit();
|
||||
}
|
||||
|
||||
row_vers_build_clust_v_col(
|
||||
row, clust_index, index, heap);
|
||||
row, clust_index, index, heap,
|
||||
vcol_info);
|
||||
|
||||
if (vcol_info && vcol_info->is_first_fetch()) {
|
||||
goto unsafe_to_purge;
|
||||
}
|
||||
|
||||
entry = row_build_index_entry(
|
||||
row, ext, index, heap);
|
||||
@ -974,7 +1023,7 @@ safe_to_purge:
|
||||
if (v_heap) {
|
||||
mem_heap_free(v_heap);
|
||||
}
|
||||
return(TRUE);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} else if (dict_index_has_virtual(index)) {
|
||||
@ -982,9 +1031,14 @@ safe_to_purge:
|
||||
deleted, but the previous version of it might not. We will
|
||||
need to get the virtual column data from undo record
|
||||
associated with current cluster index */
|
||||
|
||||
cur_vrow = row_vers_build_cur_vrow(
|
||||
also_curr, rec, clust_index, &clust_offsets,
|
||||
index, roll_ptr, trx_id, heap, v_heap, mtr);
|
||||
index, roll_ptr, trx_id, heap, v_heap, mtr, vcol_info);
|
||||
|
||||
if (vcol_info && vcol_info->is_first_fetch()) {
|
||||
goto unsafe_to_purge;
|
||||
}
|
||||
}
|
||||
|
||||
version = rec;
|
||||
@ -1003,14 +1057,14 @@ safe_to_purge:
|
||||
|
||||
if (!prev_version) {
|
||||
/* Versions end here */
|
||||
|
||||
unsafe_to_purge:
|
||||
mem_heap_free(heap);
|
||||
|
||||
if (v_heap) {
|
||||
mem_heap_free(v_heap);
|
||||
}
|
||||
|
||||
return(FALSE);
|
||||
return false;
|
||||
}
|
||||
|
||||
clust_offsets = rec_get_offsets(prev_version, clust_index,
|
||||
|
@ -35,6 +35,7 @@ Created 2012-08-21 Sunny Bains
|
||||
|
||||
#include "ut0new.h"
|
||||
#include "srv0start.h"
|
||||
#include "fil0fil.h"
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
@ -910,19 +911,10 @@ LatchDebug::check_order(
|
||||
|
||||
case SYNC_TREE_NODE:
|
||||
|
||||
{
|
||||
const latch_t* fsp_latch;
|
||||
|
||||
fsp_latch = find(latches, SYNC_FSP);
|
||||
|
||||
ut_a((fsp_latch != NULL
|
||||
&& fsp_latch->is_temp_fsp())
|
||||
|| find(latches, SYNC_INDEX_TREE) != 0
|
||||
|| find(latches, SYNC_DICT_OPERATION)
|
||||
|| basic_check(latches,
|
||||
level, SYNC_TREE_NODE - 1));
|
||||
}
|
||||
|
||||
ut_a(find(latches, SYNC_FSP) == &fil_system.temp_space->latch
|
||||
|| find(latches, SYNC_INDEX_TREE)
|
||||
|| find(latches, SYNC_DICT_OPERATION)
|
||||
|| basic_check(latches, level, SYNC_TREE_NODE - 1));
|
||||
break;
|
||||
|
||||
case SYNC_TREE_NODE_NEW:
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
Copyright (c) 1995, 2016, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 2008, Google Inc.
|
||||
Copyright (c) 2017, MariaDB Corporation.
|
||||
Copyright (c) 2017, 2018, MariaDB Corporation.
|
||||
|
||||
Portions of this file contain modifications contributed and copyrighted by
|
||||
Google, Inc. Those modifications are gratefully acknowledged and are described
|
||||
@ -1092,12 +1092,12 @@ rw_lock_own_flagged(
|
||||
|
||||
const rw_lock_debug_t* info = *it;
|
||||
|
||||
ut_ad(os_thread_eq(info->thread_id, os_thread_get_curr_id()));
|
||||
|
||||
if (info->pass != 0) {
|
||||
if (info->pass) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ut_ad(os_thread_eq(info->thread_id, os_thread_get_curr_id()));
|
||||
|
||||
switch (info->lock_type) {
|
||||
case RW_LOCK_S:
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 2007, 2015, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 2017, MariaDB Corporation.
|
||||
Copyright (c) 2017, 2018, MariaDB Corporation.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free Software
|
||||
@ -1468,26 +1468,20 @@ cache_select_table(
|
||||
trx_i_s_cache_t* cache, /*!< in: whole cache */
|
||||
enum i_s_table table) /*!< in: which table */
|
||||
{
|
||||
i_s_table_cache_t* table_cache;
|
||||
|
||||
ut_ad(rw_lock_own(cache->rw_lock, RW_LOCK_S)
|
||||
|| rw_lock_own(cache->rw_lock, RW_LOCK_X));
|
||||
ut_ad(rw_lock_own_flagged(cache->rw_lock,
|
||||
RW_LOCK_FLAG_X | RW_LOCK_FLAG_S));
|
||||
|
||||
switch (table) {
|
||||
case I_S_INNODB_TRX:
|
||||
table_cache = &cache->innodb_trx;
|
||||
break;
|
||||
return &cache->innodb_trx;
|
||||
case I_S_INNODB_LOCKS:
|
||||
table_cache = &cache->innodb_locks;
|
||||
break;
|
||||
return &cache->innodb_locks;
|
||||
case I_S_INNODB_LOCK_WAITS:
|
||||
table_cache = &cache->innodb_lock_waits;
|
||||
break;
|
||||
default:
|
||||
ut_error;
|
||||
return &cache->innodb_lock_waits;
|
||||
}
|
||||
|
||||
return(table_cache);
|
||||
ut_error;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*******************************************************************//**
|
||||
|
@ -761,7 +761,7 @@ trx_lists_init_at_db_start()
|
||||
for (undo = UT_LIST_GET_FIRST(rseg->undo_list);
|
||||
undo != NULL;
|
||||
undo = UT_LIST_GET_NEXT(undo_list, undo)) {
|
||||
trx_t *trx = trx_sys.rw_trx_hash.find(0, undo->trx_id);
|
||||
trx_t *trx = trx_sys.find(0, undo->trx_id, false);
|
||||
if (!trx) {
|
||||
trx_resurrect(undo, rseg, start_time,
|
||||
&rows_to_undo, false);
|
||||
|
@ -358,7 +358,7 @@ ut_print_buf_hex(
|
||||
|
||||
for (data = static_cast<const byte*>(buf), i = 0; i < len; i++) {
|
||||
byte b = *data++;
|
||||
o << hexdigit[(int) b >> 16] << hexdigit[b & 15];
|
||||
o << hexdigit[int(b) >> 4] << hexdigit[b & 15];
|
||||
}
|
||||
|
||||
o << ")";
|
||||
|
@ -412,9 +412,18 @@ delimiter //
|
||||
create procedure mysql.spider_plugin_installer()
|
||||
begin
|
||||
set @win_plugin := IF(@@version_compile_os like 'Win%', 1, 0);
|
||||
set @have_spider_i_s_plugin := 0;
|
||||
select @have_spider_i_s_plugin := 1 from INFORMATION_SCHEMA.plugins where PLUGIN_NAME = 'SPIDER';
|
||||
set @have_spider_plugin := 0;
|
||||
select @have_spider_plugin := 1 from INFORMATION_SCHEMA.plugins where PLUGIN_NAME = 'SPIDER';
|
||||
if @have_spider_plugin = 0 then
|
||||
select @have_spider_plugin := 1 from mysql.plugin where name = 'spider';
|
||||
if @have_spider_i_s_plugin = 0 then
|
||||
if @have_spider_plugin = 1 then
|
||||
-- spider plugin is present in mysql.plugin but not in
|
||||
-- information_schema.plugins. Remove spider plugin entry
|
||||
-- in mysql.plugin first.
|
||||
delete from mysql.plugin where name = 'spider';
|
||||
end if;
|
||||
-- Install spider plugin
|
||||
if @win_plugin = 0 then
|
||||
install plugin spider soname 'ha_spider.so';
|
||||
else
|
||||
@ -423,7 +432,16 @@ begin
|
||||
end if;
|
||||
set @have_spider_i_s_alloc_mem_plugin := 0;
|
||||
select @have_spider_i_s_alloc_mem_plugin := 1 from INFORMATION_SCHEMA.plugins where PLUGIN_NAME = 'SPIDER_ALLOC_MEM';
|
||||
if @have_spider_i_s_alloc_mem_plugin = 0 then
|
||||
set @have_spider_alloc_mem_plugin := 0;
|
||||
select @have_spider_alloc_mem_plugin := 1 from mysql.plugin where name = 'spider_alloc_mem';
|
||||
if @have_spider_i_s_alloc_mem_plugin = 0 then
|
||||
if @have_spider_alloc_mem_plugin = 1 then
|
||||
-- spider_alloc_mem plugin is present in mysql.plugin but not in
|
||||
-- information_schema.plugins. Remove spider_alloc_mem plugin entry
|
||||
-- in mysql.plugin first.
|
||||
delete from mysql.plugin where name = 'spider_alloc_mem';
|
||||
end if;
|
||||
-- Install spider_alloc_mem plugin
|
||||
if @win_plugin = 0 then
|
||||
install plugin spider_alloc_mem soname 'ha_spider.so';
|
||||
else
|
||||
|
Loading…
x
Reference in New Issue
Block a user