Merge 10.9 into 10.10
This commit is contained in:
commit
f14d9fa09a
23
mysql-test/include/ctype_unicode_casefold_bmp.inc
Normal file
23
mysql-test/include/ctype_unicode_casefold_bmp.inc
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
--source include/have_utf32.inc
|
||||||
|
--source include/have_ucs2.inc
|
||||||
|
--source include/have_sequence.inc
|
||||||
|
|
||||||
|
EXECUTE IMMEDIATE SFORMAT('
|
||||||
|
CREATE VIEW v_bmp AS
|
||||||
|
SELECT
|
||||||
|
seq AS codepoint,
|
||||||
|
LPAD(HEX(seq),4,''0'') AS codepoint_hex4,
|
||||||
|
CONVERT(CHAR(seq USING utf32) USING {}) COLLATE {} AS c
|
||||||
|
FROM
|
||||||
|
seq_0_to_65535', @@character_set_connection, @@collation_connection);
|
||||||
|
|
||||||
|
SELECT COLLATION(c) FROM v_bmp LIMIT 1;
|
||||||
|
|
||||||
|
SELECT
|
||||||
|
codepoint_hex4,
|
||||||
|
HEX(CAST(LOWER(c) AS CHAR CHARACTER SET ucs2)),
|
||||||
|
HEX(CAST(UPPER(c) AS CHAR CHARACTER SET ucs2))
|
||||||
|
FROM v_bmp
|
||||||
|
WHERE BINARY(c)<>BINARY(LOWER(c)) OR BINARY(c)<>BINARY(UPPER(c));
|
||||||
|
|
||||||
|
DROP VIEW v_bmp;
|
22
mysql-test/include/ctype_unicode_casefold_supplementary.inc
Normal file
22
mysql-test/include/ctype_unicode_casefold_supplementary.inc
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
--source include/have_utf32.inc
|
||||||
|
--source include/have_sequence.inc
|
||||||
|
|
||||||
|
EXECUTE IMMEDIATE SFORMAT('
|
||||||
|
CREATE VIEW v_supplementary AS
|
||||||
|
SELECT
|
||||||
|
seq AS codepoint,
|
||||||
|
LPAD(HEX(seq),8,''0'') AS codepoint_hex8,
|
||||||
|
CONVERT(CHAR(seq USING utf32) USING {}) COLLATE {} AS c
|
||||||
|
FROM
|
||||||
|
seq_65536_to_1114111', @@character_set_connection, @@collation_connection);
|
||||||
|
|
||||||
|
SELECT COLLATION(c) FROM v_supplementary LIMIT 1;
|
||||||
|
|
||||||
|
SELECT
|
||||||
|
codepoint_hex8,
|
||||||
|
HEX(CAST(LOWER(c) AS CHAR CHARACTER SET utf32)),
|
||||||
|
HEX(CAST(UPPER(c) AS CHAR CHARACTER SET utf32))
|
||||||
|
FROM v_supplementary
|
||||||
|
WHERE BINARY(c)<>BINARY(LOWER(c)) OR BINARY(c)<>BINARY(UPPER(c));
|
||||||
|
|
||||||
|
DROP VIEW v_supplementary;
|
26
mysql-test/include/ctype_unicode_ws_bmp.inc
Normal file
26
mysql-test/include/ctype_unicode_ws_bmp.inc
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
--source include/have_utf32.inc
|
||||||
|
--source include/have_sequence.inc
|
||||||
|
|
||||||
|
EXECUTE IMMEDIATE SFORMAT('
|
||||||
|
CREATE VIEW v_bmp AS
|
||||||
|
SELECT
|
||||||
|
seq AS codepoint,
|
||||||
|
LPAD(HEX(seq),4,''0'') AS codepoint_hex4,
|
||||||
|
CONVERT(CHAR(seq USING utf32) USING {}) COLLATE {} AS c
|
||||||
|
FROM
|
||||||
|
seq_0_to_65535', @@character_set_connection, @@collation_connection);
|
||||||
|
|
||||||
|
SELECT COLLATION(c) FROM v_bmp LIMIT 1;
|
||||||
|
|
||||||
|
SELECT HEX(codepoint) FROM v_bmp WHERE HEX(WEIGHT_STRING(c))='FFFD';
|
||||||
|
|
||||||
|
SELECT
|
||||||
|
SUM(codepoint_hex4=HEX(WEIGHT_STRING(c))) AS count_bmp_weight_is_codepoint,
|
||||||
|
SUM(codepoint_hex4<>HEX(WEIGHT_STRING(c))) AS count_bmp_weight_is_not_codepoint
|
||||||
|
FROM v_bmp;
|
||||||
|
|
||||||
|
SELECT codepoint_hex4,HEX(WEIGHT_STRING(c))
|
||||||
|
FROM v_bmp
|
||||||
|
WHERE codepoint_hex4<>HEX(WEIGHT_STRING(c));
|
||||||
|
|
||||||
|
DROP VIEW v_bmp;
|
19
mysql-test/include/ctype_unicode_ws_supplementary.inc
Normal file
19
mysql-test/include/ctype_unicode_ws_supplementary.inc
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
--source include/have_utf32.inc
|
||||||
|
--source include/have_sequence.inc
|
||||||
|
|
||||||
|
EXECUTE IMMEDIATE SFORMAT('
|
||||||
|
CREATE VIEW v_supplementary AS
|
||||||
|
SELECT
|
||||||
|
seq AS codepoint,
|
||||||
|
CONVERT(CHAR(seq USING utf32) USING {}) COLLATE {} AS c
|
||||||
|
FROM
|
||||||
|
seq_65536_to_1114111', @@character_set_connection, @@collation_connection);
|
||||||
|
|
||||||
|
SELECT COLLATION(c) FROM v_supplementary LIMIT 1;
|
||||||
|
|
||||||
|
SELECT
|
||||||
|
SUM(HEX(WEIGHT_STRING(c))<>'FFFD'),
|
||||||
|
SUM(HEX(WEIGHT_STRING(c))='FFFD')
|
||||||
|
FROM v_supplementary;
|
||||||
|
|
||||||
|
DROP VIEW v_supplementary;
|
1427
mysql-test/main/ctype_ucs2_general_ci_casefold.result
Normal file
1427
mysql-test/main/ctype_ucs2_general_ci_casefold.result
Normal file
File diff suppressed because it is too large
Load Diff
14
mysql-test/main/ctype_ucs2_general_ci_casefold.test
Normal file
14
mysql-test/main/ctype_ucs2_general_ci_casefold.test
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
--echo #
|
||||||
|
--echo # Start of 10.7 tests
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # MDEV-30716 Wrong casefolding in xxx_unicode_520_ci for U+0700..U+07FF
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
SET collation_connection=ucs2_general_ci;
|
||||||
|
--source include/ctype_unicode_casefold_bmp.inc
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # End of 10.7 tests
|
||||||
|
--echo #
|
1143
mysql-test/main/ctype_ucs2_general_ci_ws.result
Normal file
1143
mysql-test/main/ctype_ucs2_general_ci_ws.result
Normal file
File diff suppressed because it is too large
Load Diff
14
mysql-test/main/ctype_ucs2_general_ci_ws.test
Normal file
14
mysql-test/main/ctype_ucs2_general_ci_ws.test
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
--echo #
|
||||||
|
--echo # Start of 10.7 tests
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # MDEV-30716 Wrong casefolding in xxx_unicode_520_ci for U+0700..U+07FF
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
SET @@collation_connection=ucs2_general_ci;
|
||||||
|
--source include/ctype_unicode_ws_bmp.inc
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # End of 10.7 tests
|
||||||
|
--echo #
|
1427
mysql-test/main/ctype_ucs2_general_mysql500_ci_casefold.result
Normal file
1427
mysql-test/main/ctype_ucs2_general_mysql500_ci_casefold.result
Normal file
File diff suppressed because it is too large
Load Diff
15
mysql-test/main/ctype_ucs2_general_mysql500_ci_casefold.test
Normal file
15
mysql-test/main/ctype_ucs2_general_mysql500_ci_casefold.test
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
--echo #
|
||||||
|
--echo # Start of 10.7 tests
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # MDEV-30716 Wrong casefolding in xxx_unicode_520_ci for U+0700..U+07FF
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
SET @@collation_connection=ucs2_general_mysql500_ci;
|
||||||
|
--source include/ctype_unicode_casefold_bmp.inc
|
||||||
|
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # End of 10.7 tests
|
||||||
|
--echo #
|
1143
mysql-test/main/ctype_ucs2_general_mysql500_ci_ws.result
Normal file
1143
mysql-test/main/ctype_ucs2_general_mysql500_ci_ws.result
Normal file
File diff suppressed because it is too large
Load Diff
15
mysql-test/main/ctype_ucs2_general_mysql500_ci_ws.test
Normal file
15
mysql-test/main/ctype_ucs2_general_mysql500_ci_ws.test
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
--echo #
|
||||||
|
--echo # Start of 10.7 tests
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # MDEV-30716 Wrong casefolding in xxx_unicode_520_ci for U+0700..U+07FF
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
SET @@collation_connection=ucs2_general_mysql500_ci;
|
||||||
|
--source include/ctype_unicode_ws_bmp.inc
|
||||||
|
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # End of 10.7 tests
|
||||||
|
--echo #
|
1427
mysql-test/main/ctype_ucs2_turkish_ci_casefold.result
Normal file
1427
mysql-test/main/ctype_ucs2_turkish_ci_casefold.result
Normal file
File diff suppressed because it is too large
Load Diff
14
mysql-test/main/ctype_ucs2_turkish_ci_casefold.test
Normal file
14
mysql-test/main/ctype_ucs2_turkish_ci_casefold.test
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
--echo #
|
||||||
|
--echo # Start of 10.7 tests
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # MDEV-30716 Wrong casefolding in xxx_unicode_520_ci for U+0700..U+07FF
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
SET @@collation_connection=ucs2_turkish_ci;
|
||||||
|
--source include/ctype_unicode_casefold_bmp.inc
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # End of 10.7 tests
|
||||||
|
--echo #
|
2011
mysql-test/main/ctype_ucs2_unicode_520_ci_casefold.result
Normal file
2011
mysql-test/main/ctype_ucs2_unicode_520_ci_casefold.result
Normal file
File diff suppressed because it is too large
Load Diff
14
mysql-test/main/ctype_ucs2_unicode_520_ci_casefold.test
Normal file
14
mysql-test/main/ctype_ucs2_unicode_520_ci_casefold.test
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
--echo #
|
||||||
|
--echo # Start of 10.7 tests
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # MDEV-30716 Wrong casefolding in xxx_unicode_520_ci for U+0700..U+07FF
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
SET @@collation_connection=ucs2_unicode_520_ci;
|
||||||
|
--source include/ctype_unicode_casefold_bmp.inc
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # End of 10.7 tests
|
||||||
|
--echo #
|
1427
mysql-test/main/ctype_utf8mb3_general_ci_casefold.result
Normal file
1427
mysql-test/main/ctype_utf8mb3_general_ci_casefold.result
Normal file
File diff suppressed because it is too large
Load Diff
14
mysql-test/main/ctype_utf8mb3_general_ci_casefold.test
Normal file
14
mysql-test/main/ctype_utf8mb3_general_ci_casefold.test
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
--echo #
|
||||||
|
--echo # Start of 10.7 tests
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # MDEV-30716 Wrong casefolding in xxx_unicode_520_ci for U+0700..U+07FF
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
SET NAMES utf8mb3 COLLATE utf8mb3_general_ci;
|
||||||
|
--source include/ctype_unicode_casefold_bmp.inc
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # End of 10.7 tests
|
||||||
|
--echo #
|
1143
mysql-test/main/ctype_utf8mb3_general_ci_ws.result
Normal file
1143
mysql-test/main/ctype_utf8mb3_general_ci_ws.result
Normal file
File diff suppressed because it is too large
Load Diff
14
mysql-test/main/ctype_utf8mb3_general_ci_ws.test
Normal file
14
mysql-test/main/ctype_utf8mb3_general_ci_ws.test
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
--echo #
|
||||||
|
--echo # Start of 10.7 tests
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # MDEV-30716 Wrong casefolding in xxx_unicode_520_ci for U+0700..U+07FF
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
SET NAMES utf8mb3 COLLATE utf8mb3_general_ci;
|
||||||
|
--source include/ctype_unicode_ws_bmp.inc
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # End of 10.7 tests
|
||||||
|
--echo #
|
1427
mysql-test/main/ctype_utf8mb3_general_mysql500_ci_casefold.result
Normal file
1427
mysql-test/main/ctype_utf8mb3_general_mysql500_ci_casefold.result
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,15 @@
|
|||||||
|
--echo #
|
||||||
|
--echo # Start of 10.7 tests
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # MDEV-30716 Wrong casefolding in xxx_unicode_520_ci for U+0700..U+07FF
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
SET NAMES utf8mb3 COLLATE utf8mb3_general_mysql500_ci;
|
||||||
|
--source include/ctype_unicode_casefold_bmp.inc
|
||||||
|
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # End of 10.7 tests
|
||||||
|
--echo #
|
1142
mysql-test/main/ctype_utf8mb3_general_mysql500_ci_ws.result
Normal file
1142
mysql-test/main/ctype_utf8mb3_general_mysql500_ci_ws.result
Normal file
File diff suppressed because it is too large
Load Diff
15
mysql-test/main/ctype_utf8mb3_general_mysql500_ci_ws.test
Normal file
15
mysql-test/main/ctype_utf8mb3_general_mysql500_ci_ws.test
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
--echo #
|
||||||
|
--echo # Start of 10.7 tests
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # MDEV-30716 Wrong casefolding in xxx_unicode_520_ci for U+0700..U+07FF
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
SET NAMES utf8mb3 COLLATE utf8mb3_general_mysql500_ci;
|
||||||
|
--source include/ctype_unicode_ws_bmp.inc
|
||||||
|
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # End of 10.7 tests
|
||||||
|
--echo #
|
1427
mysql-test/main/ctype_utf8mb3_turkish_ci_casefold.result
Normal file
1427
mysql-test/main/ctype_utf8mb3_turkish_ci_casefold.result
Normal file
File diff suppressed because it is too large
Load Diff
14
mysql-test/main/ctype_utf8mb3_turkish_ci_casefold.test
Normal file
14
mysql-test/main/ctype_utf8mb3_turkish_ci_casefold.test
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
--echo #
|
||||||
|
--echo # Start of 10.7 tests
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # MDEV-30716 Wrong casefolding in xxx_unicode_520_ci for U+0700..U+07FF
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
SET NAMES utf8mb3 COLLATE utf8mb3_turkish_ci;
|
||||||
|
--source include/ctype_unicode_casefold_bmp.inc
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # End of 10.7 tests
|
||||||
|
--echo #
|
2011
mysql-test/main/ctype_utf8mb3_unicode_520_ci_casefold.result
Normal file
2011
mysql-test/main/ctype_utf8mb3_unicode_520_ci_casefold.result
Normal file
File diff suppressed because it is too large
Load Diff
14
mysql-test/main/ctype_utf8mb3_unicode_520_ci_casefold.test
Normal file
14
mysql-test/main/ctype_utf8mb3_unicode_520_ci_casefold.test
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
--echo #
|
||||||
|
--echo # Start of 10.7 tests
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # MDEV-30716 Wrong casefolding in xxx_unicode_520_ci for U+0700..U+07FF
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
SET NAMES utf8mb3 COLLATE utf8mb3_unicode_520_ci;
|
||||||
|
--source include/ctype_unicode_casefold_bmp.inc
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # End of 10.7 tests
|
||||||
|
--echo #
|
1446
mysql-test/main/ctype_utf8mb4_general_ci_casefold.result
Normal file
1446
mysql-test/main/ctype_utf8mb4_general_ci_casefold.result
Normal file
File diff suppressed because it is too large
Load Diff
15
mysql-test/main/ctype_utf8mb4_general_ci_casefold.test
Normal file
15
mysql-test/main/ctype_utf8mb4_general_ci_casefold.test
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
--echo #
|
||||||
|
--echo # Start of 10.7 tests
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # MDEV-30716 Wrong casefolding in xxx_unicode_520_ci for U+0700..U+07FF
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
SET NAMES utf8mb4 COLLATE utf8mb4_general_ci;
|
||||||
|
--source include/ctype_unicode_casefold_bmp.inc
|
||||||
|
--source include/ctype_unicode_casefold_supplementary.inc
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # End of 10.7 tests
|
||||||
|
--echo #
|
1160
mysql-test/main/ctype_utf8mb4_general_ci_ws.result
Normal file
1160
mysql-test/main/ctype_utf8mb4_general_ci_ws.result
Normal file
File diff suppressed because it is too large
Load Diff
16
mysql-test/main/ctype_utf8mb4_general_ci_ws.test
Normal file
16
mysql-test/main/ctype_utf8mb4_general_ci_ws.test
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
--echo #
|
||||||
|
--echo # Start of 10.7 tests
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # MDEV-30716 Wrong casefolding in xxx_unicode_520_ci for U+0700..U+07FF
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
SET NAMES utf8mb4 COLLATE utf8mb4_general_ci;
|
||||||
|
--source include/ctype_unicode_ws_bmp.inc
|
||||||
|
--source include/ctype_unicode_ws_supplementary.inc
|
||||||
|
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # End of 10.7 tests
|
||||||
|
--echo #
|
1446
mysql-test/main/ctype_utf8mb4_turkish_ci_casefold.result
Normal file
1446
mysql-test/main/ctype_utf8mb4_turkish_ci_casefold.result
Normal file
File diff suppressed because it is too large
Load Diff
15
mysql-test/main/ctype_utf8mb4_turkish_ci_casefold.test
Normal file
15
mysql-test/main/ctype_utf8mb4_turkish_ci_casefold.test
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
--echo #
|
||||||
|
--echo # Start of 10.7 tests
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # MDEV-30716 Wrong casefolding in xxx_unicode_520_ci for U+0700..U+07FF
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
SET NAMES utf8mb4 COLLATE utf8mb4_turkish_ci;
|
||||||
|
--source include/ctype_unicode_casefold_bmp.inc
|
||||||
|
--source include/ctype_unicode_casefold_supplementary.inc
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # End of 10.7 tests
|
||||||
|
--echo #
|
2110
mysql-test/main/ctype_utf8mb4_unicode_520_ci_casefold.result
Normal file
2110
mysql-test/main/ctype_utf8mb4_unicode_520_ci_casefold.result
Normal file
File diff suppressed because it is too large
Load Diff
15
mysql-test/main/ctype_utf8mb4_unicode_520_ci_casefold.test
Normal file
15
mysql-test/main/ctype_utf8mb4_unicode_520_ci_casefold.test
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
--echo #
|
||||||
|
--echo # Start of 10.7 tests
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # MDEV-30716 Wrong casefolding in xxx_unicode_520_ci for U+0700..U+07FF
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
SET NAMES utf8mb4 COLLATE utf8mb4_unicode_520_ci;
|
||||||
|
--source include/ctype_unicode_casefold_bmp.inc
|
||||||
|
--source include/ctype_unicode_casefold_supplementary.inc
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # End of 10.7 tests
|
||||||
|
--echo #
|
1446
mysql-test/main/ctype_utf8mb4_unicode_ci_casefold.result
Normal file
1446
mysql-test/main/ctype_utf8mb4_unicode_ci_casefold.result
Normal file
File diff suppressed because it is too large
Load Diff
15
mysql-test/main/ctype_utf8mb4_unicode_ci_casefold.test
Normal file
15
mysql-test/main/ctype_utf8mb4_unicode_ci_casefold.test
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
--echo #
|
||||||
|
--echo # Start of 10.7 tests
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # MDEV-30716 Wrong casefolding in xxx_unicode_520_ci for U+0700..U+07FF
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||||
|
--source include/ctype_unicode_casefold_bmp.inc
|
||||||
|
--source include/ctype_unicode_casefold_supplementary.inc
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # End of 10.7 tests
|
||||||
|
--echo #
|
@ -1,7 +1,11 @@
|
|||||||
|
SET @save_frequency=@@GLOBAL.innodb_purge_rseg_truncate_frequency;
|
||||||
|
SET @save_dbug=@@GLOBAL.debug_dbug;
|
||||||
|
SET GLOBAL innodb_purge_rseg_truncate_frequency=1;
|
||||||
CREATE TABLE t1(f1 INT NOT NULL, f2 int not null,
|
CREATE TABLE t1(f1 INT NOT NULL, f2 int not null,
|
||||||
f3 int generated always as (f2 * 2) VIRTUAL,
|
f3 int generated always as (f2 * 2) VIRTUAL,
|
||||||
primary key(f1), INDEX (f3))ENGINE=InnoDB;
|
primary key(f1), INDEX (f3))ENGINE=InnoDB;
|
||||||
connect con1,localhost,root,,,;
|
connect con1,localhost,root,,,;
|
||||||
|
InnoDB 0 transactions not purged
|
||||||
START TRANSACTION WITH CONSISTENT SNAPSHOT;
|
START TRANSACTION WITH CONSISTENT SNAPSHOT;
|
||||||
connection default;
|
connection default;
|
||||||
INSERT INTO t1(f1, f2) VALUES(1,2);
|
INSERT INTO t1(f1, f2) VALUES(1,2);
|
||||||
@ -18,5 +22,6 @@ commit;
|
|||||||
disconnect con1;
|
disconnect con1;
|
||||||
disconnect con2;
|
disconnect con2;
|
||||||
connection default;
|
connection default;
|
||||||
set global debug_dbug=default;
|
SET GLOBAL innodb_purge_rseg_truncate_frequency=@save_frequency;
|
||||||
|
SET GLOBAL debug_dbug=@save_dbug;
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
|
@ -1,9 +1,14 @@
|
|||||||
--source include/have_innodb.inc
|
--source include/have_innodb.inc
|
||||||
--source include/have_debug.inc
|
--source include/have_debug.inc
|
||||||
|
|
||||||
|
SET @save_frequency=@@GLOBAL.innodb_purge_rseg_truncate_frequency;
|
||||||
|
SET @save_dbug=@@GLOBAL.debug_dbug;
|
||||||
|
SET GLOBAL innodb_purge_rseg_truncate_frequency=1;
|
||||||
CREATE TABLE t1(f1 INT NOT NULL, f2 int not null,
|
CREATE TABLE t1(f1 INT NOT NULL, f2 int not null,
|
||||||
f3 int generated always as (f2 * 2) VIRTUAL,
|
f3 int generated always as (f2 * 2) VIRTUAL,
|
||||||
primary key(f1), INDEX (f3))ENGINE=InnoDB;
|
primary key(f1), INDEX (f3))ENGINE=InnoDB;
|
||||||
connect(con1,localhost,root,,,);
|
connect(con1,localhost,root,,,);
|
||||||
|
--source ../innodb/include/wait_all_purged.inc
|
||||||
START TRANSACTION WITH CONSISTENT SNAPSHOT;
|
START TRANSACTION WITH CONSISTENT SNAPSHOT;
|
||||||
|
|
||||||
connection default;
|
connection default;
|
||||||
@ -26,5 +31,6 @@ commit;
|
|||||||
disconnect con1;
|
disconnect con1;
|
||||||
disconnect con2;
|
disconnect con2;
|
||||||
connection default;
|
connection default;
|
||||||
set global debug_dbug=default;
|
SET GLOBAL innodb_purge_rseg_truncate_frequency=@save_frequency;
|
||||||
|
SET GLOBAL debug_dbug=@save_dbug;
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
|
SET @save_freq=@@GLOBAL.innodb_purge_rseg_truncate_frequency;
|
||||||
|
SET GLOBAL innodb_purge_rseg_truncate_frequency=1;
|
||||||
CREATE TABLE t (a int PRIMARY KEY, b int NOT NULL UNIQUE) engine = InnoDB;
|
CREATE TABLE t (a int PRIMARY KEY, b int NOT NULL UNIQUE) engine = InnoDB;
|
||||||
|
InnoDB 0 transactions not purged
|
||||||
connect prevent_purge,localhost,root,,;
|
connect prevent_purge,localhost,root,,;
|
||||||
start transaction with consistent snapshot;
|
start transaction with consistent snapshot;
|
||||||
connect con_del_1,localhost,root,,;
|
connect con_del_1,localhost,root,,;
|
||||||
@ -34,3 +37,4 @@ disconnect con_del_2;
|
|||||||
connection default;
|
connection default;
|
||||||
SET DEBUG_SYNC = 'RESET';
|
SET DEBUG_SYNC = 'RESET';
|
||||||
DROP TABLE t;
|
DROP TABLE t;
|
||||||
|
SET GLOBAL innodb_purge_rseg_truncate_frequency=@save_freq;
|
||||||
|
@ -7,6 +7,7 @@ SET GLOBAL innodb_purge_rseg_truncate_frequency = 1;
|
|||||||
SET GLOBAL innodb_purge_rseg_truncate_frequency = 1;
|
SET GLOBAL innodb_purge_rseg_truncate_frequency = 1;
|
||||||
CREATE TABLE t1(a INT PRIMARY KEY, b INT NOT NULL)
|
CREATE TABLE t1(a INT PRIMARY KEY, b INT NOT NULL)
|
||||||
ROW_FORMAT=REDUNDANT ENGINE=InnoDB;
|
ROW_FORMAT=REDUNDANT ENGINE=InnoDB;
|
||||||
|
InnoDB 0 transactions not purged
|
||||||
connect prevent_purge,localhost,root;
|
connect prevent_purge,localhost,root;
|
||||||
START TRANSACTION WITH CONSISTENT SNAPSHOT;
|
START TRANSACTION WITH CONSISTENT SNAPSHOT;
|
||||||
connection default;
|
connection default;
|
||||||
@ -19,7 +20,11 @@ UPDATE t1 SET b=4 WHERE a=3;
|
|||||||
disconnect prevent_purge;
|
disconnect prevent_purge;
|
||||||
connection default;
|
connection default;
|
||||||
InnoDB 0 transactions not purged
|
InnoDB 0 transactions not purged
|
||||||
|
connection con1;
|
||||||
|
ROLLBACK;
|
||||||
disconnect con1;
|
disconnect con1;
|
||||||
|
connection default;
|
||||||
|
InnoDB 0 transactions not purged
|
||||||
FLUSH TABLE t1 FOR EXPORT;
|
FLUSH TABLE t1 FOR EXPORT;
|
||||||
Clustered index root page contents:
|
Clustered index root page contents:
|
||||||
N_RECS=3; LEVEL=0
|
N_RECS=3; LEVEL=0
|
||||||
|
@ -3,6 +3,7 @@ SET GLOBAL innodb_purge_rseg_truncate_frequency=1;
|
|||||||
CREATE TABLE t1(id INT PRIMARY key, val VARCHAR(16000)) ENGINE=InnoDB;
|
CREATE TABLE t1(id INT PRIMARY key, val VARCHAR(16000)) ENGINE=InnoDB;
|
||||||
INSERT INTO t1 (id,val) SELECT 2*seq,'x' FROM seq_0_to_1023;
|
INSERT INTO t1 (id,val) SELECT 2*seq,'x' FROM seq_0_to_1023;
|
||||||
connect con1,localhost,root,,;
|
connect con1,localhost,root,,;
|
||||||
|
InnoDB 0 transactions not purged
|
||||||
START TRANSACTION WITH CONSISTENT SNAPSHOT;
|
START TRANSACTION WITH CONSISTENT SNAPSHOT;
|
||||||
connection default;
|
connection default;
|
||||||
DELETE FROM t1 WHERE id=1788;
|
DELETE FROM t1 WHERE id=1788;
|
||||||
|
@ -9,12 +9,10 @@ SET GLOBAL innodb_purge_rseg_truncate_frequency= 1;
|
|||||||
CREATE PROCEDURE insert_n(start int, end int)
|
CREATE PROCEDURE insert_n(start int, end int)
|
||||||
BEGIN
|
BEGIN
|
||||||
DECLARE i INT DEFAULT start;
|
DECLARE i INT DEFAULT start;
|
||||||
START TRANSACTION;
|
|
||||||
WHILE i <= end do
|
WHILE i <= end do
|
||||||
INSERT INTO t1 VALUES (1, 2, 3) ON DUPLICATE KEY UPDATE c = i;
|
INSERT INTO t1 VALUES (1, 2, 3) ON DUPLICATE KEY UPDATE c = i;
|
||||||
SET i = i + 1;
|
SET i = i + 1;
|
||||||
END WHILE;
|
END WHILE;
|
||||||
COMMIT;
|
|
||||||
END~~
|
END~~
|
||||||
CREATE FUNCTION num_pages_get()
|
CREATE FUNCTION num_pages_get()
|
||||||
RETURNS INT
|
RETURNS INT
|
||||||
@ -30,6 +28,7 @@ END~~
|
|||||||
#
|
#
|
||||||
CREATE TABLE t1 (a INT, b INT, c INT, PRIMARY KEY(a,b), KEY (b,c))
|
CREATE TABLE t1 (a INT, b INT, c INT, PRIMARY KEY(a,b), KEY (b,c))
|
||||||
ENGINE=InnoDB STATS_PERSISTENT=0;
|
ENGINE=InnoDB STATS_PERSISTENT=0;
|
||||||
|
InnoDB 0 transactions not purged
|
||||||
BEGIN;
|
BEGIN;
|
||||||
SELECT * FROM t1;
|
SELECT * FROM t1;
|
||||||
a b c
|
a b c
|
||||||
@ -38,20 +37,24 @@ a b c
|
|||||||
#
|
#
|
||||||
connect con2, localhost, root,,;
|
connect con2, localhost, root,,;
|
||||||
connection con2;
|
connection con2;
|
||||||
|
BEGIN;
|
||||||
INSERT INTO t1 VALUES (1, 2, 3) ON DUPLICATE KEY UPDATE c = NULL;
|
INSERT INTO t1 VALUES (1, 2, 3) ON DUPLICATE KEY UPDATE c = NULL;
|
||||||
CALL insert_n(1, 50);;
|
CALL insert_n(1, 50);;
|
||||||
connect con3, localhost, root,,;
|
connect con3, localhost, root,,;
|
||||||
connection con3;
|
connection con3;
|
||||||
|
BEGIN;
|
||||||
CALL insert_n(51, 100);;
|
CALL insert_n(51, 100);;
|
||||||
connection con2;
|
connection con2;
|
||||||
|
COMMIT;
|
||||||
connection con3;
|
connection con3;
|
||||||
INSERT INTO t1 VALUES (1, 2, 1) ON DUPLICATE KEY UPDATE c = NULL;
|
INSERT INTO t1 VALUES (1, 2, 1) ON DUPLICATE KEY UPDATE c = NULL;
|
||||||
|
COMMIT;
|
||||||
connection default;
|
connection default;
|
||||||
#
|
#
|
||||||
# Connect to default and record how many pages were accessed
|
# Connect to default and record how many pages were accessed
|
||||||
# when selecting the record using the secondary key.
|
# when selecting the record using the secondary key.
|
||||||
#
|
#
|
||||||
InnoDB 4 transactions not purged
|
InnoDB 2 transactions not purged
|
||||||
SET @num_pages_1 = num_pages_get();
|
SET @num_pages_1 = num_pages_get();
|
||||||
SELECT * FROM t1 force index (b);
|
SELECT * FROM t1 force index (b);
|
||||||
a b c
|
a b c
|
||||||
|
34
mysql-test/suite/innodb/r/lock_move_wait_lock_race.result
Normal file
34
mysql-test/suite/innodb/r/lock_move_wait_lock_race.result
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
CREATE TABLE t (pk int PRIMARY KEY, c varchar(10)) ENGINE=InnoDB;
|
||||||
|
INSERT INTO t VALUES (10, "0123456789");
|
||||||
|
connection default;
|
||||||
|
BEGIN;
|
||||||
|
SELECT * FROM t WHERE c = 10 FOR UPDATE;
|
||||||
|
pk c
|
||||||
|
connect trx2, localhost,root,,;
|
||||||
|
BEGIN;
|
||||||
|
SET DEBUG_SYNC="lock_wait_start SIGNAL trx2_start_waiting";
|
||||||
|
SET DEBUG_SYNC="lock_wait_end SIGNAL trx2_wait_end WAIT_FOR trx2_cont_upd";
|
||||||
|
SET DEBUG_SYNC="lock_rec_store_on_page_infimum_end SIGNAL trx2_moved_locks WAIT_FOR trx2_cont";
|
||||||
|
UPDATE t SET c = NULL WHERE pk = 10;
|
||||||
|
connect trx3, localhost,root,,;
|
||||||
|
SET DEBUG_SYNC="now WAIT_FOR trx2_start_waiting";
|
||||||
|
SET innodb_lock_wait_timeout=1;
|
||||||
|
BEGIN;
|
||||||
|
SET DEBUG_SYNC="lock_wait_start SIGNAL trx3_start_waiting WAIT_FOR trx3_cont_waiting";
|
||||||
|
SET DEBUG_SYNC="lock_sys_t_cancel_enter SIGNAL trx3_cancel_enter WAIT_FOR trx3_cont_cancel_waiting";
|
||||||
|
UPDATE t SET c = "abcdefghij" WHERE pk = 10;
|
||||||
|
connection default;
|
||||||
|
SET DEBUG_SYNC="now WAIT_FOR trx3_start_waiting";
|
||||||
|
COMMIT;
|
||||||
|
SET DEBUG_SYNC="now WAIT_FOR trx2_wait_end";
|
||||||
|
SET DEBUG_SYNC="now SIGNAL trx3_cont_waiting";
|
||||||
|
SET DEBUG_SYNC="now WAIT_FOR trx3_cancel_enter";
|
||||||
|
SET DEBUG_SYNC="now SIGNAL trx2_cont_upd";
|
||||||
|
SET DEBUG_SYNC="now WAIT_FOR trx2_moved_locks";
|
||||||
|
SET DEBUG_SYNC="now SIGNAL trx3_cont_cancel_waiting";
|
||||||
|
SET DEBUG_SYNC="now SIGNAL trx2_cont";
|
||||||
|
disconnect trx2;
|
||||||
|
disconnect trx3;
|
||||||
|
connection default;
|
||||||
|
SET DEBUG_SYNC="RESET";
|
||||||
|
DROP TABLE t;
|
@ -3,8 +3,11 @@
|
|||||||
source include/have_debug.inc;
|
source include/have_debug.inc;
|
||||||
source include/have_debug_sync.inc;
|
source include/have_debug_sync.inc;
|
||||||
|
|
||||||
|
SET @save_freq=@@GLOBAL.innodb_purge_rseg_truncate_frequency;
|
||||||
|
SET GLOBAL innodb_purge_rseg_truncate_frequency=1;
|
||||||
CREATE TABLE t (a int PRIMARY KEY, b int NOT NULL UNIQUE) engine = InnoDB;
|
CREATE TABLE t (a int PRIMARY KEY, b int NOT NULL UNIQUE) engine = InnoDB;
|
||||||
|
|
||||||
|
--source include/wait_all_purged.inc
|
||||||
--connect(prevent_purge,localhost,root,,)
|
--connect(prevent_purge,localhost,root,,)
|
||||||
start transaction with consistent snapshot;
|
start transaction with consistent snapshot;
|
||||||
|
|
||||||
@ -80,4 +83,5 @@ INSERT INTO t VALUES(30, 20);
|
|||||||
|
|
||||||
SET DEBUG_SYNC = 'RESET';
|
SET DEBUG_SYNC = 'RESET';
|
||||||
DROP TABLE t;
|
DROP TABLE t;
|
||||||
|
SET GLOBAL innodb_purge_rseg_truncate_frequency=@save_freq;
|
||||||
--source include/wait_until_count_sessions.inc
|
--source include/wait_until_count_sessions.inc
|
||||||
|
@ -14,6 +14,7 @@ SET GLOBAL innodb_purge_rseg_truncate_frequency = 1;
|
|||||||
|
|
||||||
CREATE TABLE t1(a INT PRIMARY KEY, b INT NOT NULL)
|
CREATE TABLE t1(a INT PRIMARY KEY, b INT NOT NULL)
|
||||||
ROW_FORMAT=REDUNDANT ENGINE=InnoDB;
|
ROW_FORMAT=REDUNDANT ENGINE=InnoDB;
|
||||||
|
--source include/wait_all_purged.inc
|
||||||
|
|
||||||
--connect (prevent_purge,localhost,root)
|
--connect (prevent_purge,localhost,root)
|
||||||
START TRANSACTION WITH CONSISTENT SNAPSHOT;
|
START TRANSACTION WITH CONSISTENT SNAPSHOT;
|
||||||
@ -33,7 +34,12 @@ UPDATE t1 SET b=4 WHERE a=3;
|
|||||||
# Initiate a full purge, which should reset the DB_TRX_ID except for a=3.
|
# Initiate a full purge, which should reset the DB_TRX_ID except for a=3.
|
||||||
--source include/wait_all_purged.inc
|
--source include/wait_all_purged.inc
|
||||||
# Initiate a ROLLBACK of the update, which should reset the DB_TRX_ID for a=3.
|
# Initiate a ROLLBACK of the update, which should reset the DB_TRX_ID for a=3.
|
||||||
|
--connection con1
|
||||||
|
ROLLBACK;
|
||||||
--disconnect con1
|
--disconnect con1
|
||||||
|
--connection default
|
||||||
|
# Reset the DB_TRX_ID for the hidden ADD COLUMN metadata record.
|
||||||
|
--source include/wait_all_purged.inc
|
||||||
|
|
||||||
FLUSH TABLE t1 FOR EXPORT;
|
FLUSH TABLE t1 FOR EXPORT;
|
||||||
# The following is based on innodb.table_flags:
|
# The following is based on innodb.table_flags:
|
||||||
|
@ -9,6 +9,7 @@ CREATE TABLE t1(id INT PRIMARY key, val VARCHAR(16000)) ENGINE=InnoDB;
|
|||||||
INSERT INTO t1 (id,val) SELECT 2*seq,'x' FROM seq_0_to_1023;
|
INSERT INTO t1 (id,val) SELECT 2*seq,'x' FROM seq_0_to_1023;
|
||||||
|
|
||||||
connect(con1,localhost,root,,);
|
connect(con1,localhost,root,,);
|
||||||
|
source include/wait_all_purged.inc;
|
||||||
# Prevent purge.
|
# Prevent purge.
|
||||||
START TRANSACTION WITH CONSISTENT SNAPSHOT;
|
START TRANSACTION WITH CONSISTENT SNAPSHOT;
|
||||||
connection default;
|
connection default;
|
||||||
|
@ -13,12 +13,10 @@ DELIMITER ~~;
|
|||||||
CREATE PROCEDURE insert_n(start int, end int)
|
CREATE PROCEDURE insert_n(start int, end int)
|
||||||
BEGIN
|
BEGIN
|
||||||
DECLARE i INT DEFAULT start;
|
DECLARE i INT DEFAULT start;
|
||||||
START TRANSACTION;
|
|
||||||
WHILE i <= end do
|
WHILE i <= end do
|
||||||
INSERT INTO t1 VALUES (1, 2, 3) ON DUPLICATE KEY UPDATE c = i;
|
INSERT INTO t1 VALUES (1, 2, 3) ON DUPLICATE KEY UPDATE c = i;
|
||||||
SET i = i + 1;
|
SET i = i + 1;
|
||||||
END WHILE;
|
END WHILE;
|
||||||
COMMIT;
|
|
||||||
END~~
|
END~~
|
||||||
|
|
||||||
CREATE FUNCTION num_pages_get()
|
CREATE FUNCTION num_pages_get()
|
||||||
@ -37,6 +35,7 @@ DELIMITER ;~~
|
|||||||
--echo #
|
--echo #
|
||||||
CREATE TABLE t1 (a INT, b INT, c INT, PRIMARY KEY(a,b), KEY (b,c))
|
CREATE TABLE t1 (a INT, b INT, c INT, PRIMARY KEY(a,b), KEY (b,c))
|
||||||
ENGINE=InnoDB STATS_PERSISTENT=0;
|
ENGINE=InnoDB STATS_PERSISTENT=0;
|
||||||
|
--source include/wait_all_purged.inc
|
||||||
BEGIN;
|
BEGIN;
|
||||||
SELECT * FROM t1;
|
SELECT * FROM t1;
|
||||||
|
|
||||||
@ -45,18 +44,22 @@ SELECT * FROM t1;
|
|||||||
--echo #
|
--echo #
|
||||||
connect (con2, localhost, root,,);
|
connect (con2, localhost, root,,);
|
||||||
connection con2;
|
connection con2;
|
||||||
|
BEGIN;
|
||||||
INSERT INTO t1 VALUES (1, 2, 3) ON DUPLICATE KEY UPDATE c = NULL;
|
INSERT INTO t1 VALUES (1, 2, 3) ON DUPLICATE KEY UPDATE c = NULL;
|
||||||
--send CALL insert_n(1, 50);
|
--send CALL insert_n(1, 50);
|
||||||
|
|
||||||
connect (con3, localhost, root,,);
|
connect (con3, localhost, root,,);
|
||||||
connection con3;
|
connection con3;
|
||||||
|
BEGIN;
|
||||||
--send CALL insert_n(51, 100);
|
--send CALL insert_n(51, 100);
|
||||||
|
|
||||||
connection con2;
|
connection con2;
|
||||||
reap;
|
reap;
|
||||||
|
COMMIT;
|
||||||
connection con3;
|
connection con3;
|
||||||
reap;
|
reap;
|
||||||
INSERT INTO t1 VALUES (1, 2, 1) ON DUPLICATE KEY UPDATE c = NULL;
|
INSERT INTO t1 VALUES (1, 2, 1) ON DUPLICATE KEY UPDATE c = NULL;
|
||||||
|
COMMIT;
|
||||||
|
|
||||||
connection default;
|
connection default;
|
||||||
|
|
||||||
@ -64,7 +67,7 @@ connection default;
|
|||||||
--echo # Connect to default and record how many pages were accessed
|
--echo # Connect to default and record how many pages were accessed
|
||||||
--echo # when selecting the record using the secondary key.
|
--echo # when selecting the record using the secondary key.
|
||||||
--echo #
|
--echo #
|
||||||
--let $wait_all_purged=4
|
--let $wait_all_purged=2
|
||||||
--source include/wait_all_purged.inc
|
--source include/wait_all_purged.inc
|
||||||
SET @num_pages_1 = num_pages_get();
|
SET @num_pages_1 = num_pages_get();
|
||||||
SELECT * FROM t1 force index (b);
|
SELECT * FROM t1 force index (b);
|
||||||
|
58
mysql-test/suite/innodb/t/lock_move_wait_lock_race.test
Normal file
58
mysql-test/suite/innodb/t/lock_move_wait_lock_race.test
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
--source include/have_innodb.inc
|
||||||
|
--source include/count_sessions.inc
|
||||||
|
--source include/have_debug.inc
|
||||||
|
--source include/have_debug_sync.inc
|
||||||
|
|
||||||
|
CREATE TABLE t (pk int PRIMARY KEY, c varchar(10)) ENGINE=InnoDB;
|
||||||
|
INSERT INTO t VALUES (10, "0123456789");
|
||||||
|
|
||||||
|
--connection default
|
||||||
|
BEGIN;
|
||||||
|
SELECT * FROM t WHERE c = 10 FOR UPDATE;
|
||||||
|
|
||||||
|
--connect(trx2, localhost,root,,)
|
||||||
|
BEGIN;
|
||||||
|
SET DEBUG_SYNC="lock_wait_start SIGNAL trx2_start_waiting";
|
||||||
|
SET DEBUG_SYNC="lock_wait_end SIGNAL trx2_wait_end WAIT_FOR trx2_cont_upd";
|
||||||
|
SET DEBUG_SYNC="lock_rec_store_on_page_infimum_end SIGNAL trx2_moved_locks WAIT_FOR trx2_cont";
|
||||||
|
#################
|
||||||
|
# We need to update clustered record without changing ordering fields and
|
||||||
|
# changing the size of non-ordering fields to cause locks moving from deleted
|
||||||
|
# record to infimum.
|
||||||
|
###
|
||||||
|
--send UPDATE t SET c = NULL WHERE pk = 10
|
||||||
|
|
||||||
|
|
||||||
|
--connect(trx3, localhost,root,,)
|
||||||
|
SET DEBUG_SYNC="now WAIT_FOR trx2_start_waiting";
|
||||||
|
#################
|
||||||
|
# The condition wariable waiting in lock_wait() must be finished by timeout
|
||||||
|
###
|
||||||
|
SET innodb_lock_wait_timeout=1;
|
||||||
|
BEGIN;
|
||||||
|
SET DEBUG_SYNC="lock_wait_start SIGNAL trx3_start_waiting WAIT_FOR trx3_cont_waiting";
|
||||||
|
SET DEBUG_SYNC="lock_sys_t_cancel_enter SIGNAL trx3_cancel_enter WAIT_FOR trx3_cont_cancel_waiting";
|
||||||
|
--send UPDATE t SET c = "abcdefghij" WHERE pk = 10
|
||||||
|
|
||||||
|
--connection default
|
||||||
|
SET DEBUG_SYNC="now WAIT_FOR trx3_start_waiting";
|
||||||
|
COMMIT;
|
||||||
|
SET DEBUG_SYNC="now WAIT_FOR trx2_wait_end";
|
||||||
|
SET DEBUG_SYNC="now SIGNAL trx3_cont_waiting";
|
||||||
|
SET DEBUG_SYNC="now WAIT_FOR trx3_cancel_enter";
|
||||||
|
SET DEBUG_SYNC="now SIGNAL trx2_cont_upd";
|
||||||
|
SET DEBUG_SYNC="now WAIT_FOR trx2_moved_locks";
|
||||||
|
#################
|
||||||
|
# If the bug is not fixed, there will be assertion failure here, because trx2
|
||||||
|
# moved trx3 lock from deleted record to infimum when trx3 tried to cancel the
|
||||||
|
# lock.
|
||||||
|
###
|
||||||
|
SET DEBUG_SYNC="now SIGNAL trx3_cont_cancel_waiting";
|
||||||
|
SET DEBUG_SYNC="now SIGNAL trx2_cont";
|
||||||
|
|
||||||
|
--disconnect trx2
|
||||||
|
--disconnect trx3
|
||||||
|
--connection default
|
||||||
|
SET DEBUG_SYNC="RESET";
|
||||||
|
DROP TABLE t;
|
||||||
|
--source include/wait_until_count_sessions.inc
|
@ -31,5 +31,33 @@ set DEBUG_SYNC= 'now SIGNAL fts_drop_index';
|
|||||||
connection con1;
|
connection con1;
|
||||||
drop table t1, t2;
|
drop table t1, t2;
|
||||||
connection default;
|
connection default;
|
||||||
set DEBUG_SYNC=RESET;
|
|
||||||
SET @@GLOBAL.debug_dbug = @saved_dbug;
|
SET @@GLOBAL.debug_dbug = @saved_dbug;
|
||||||
|
disconnect con1;
|
||||||
|
#
|
||||||
|
# MDEV-25984 Assertion `max_doc_id > 0' failed in fts_init_doc_id()
|
||||||
|
#
|
||||||
|
call mtr.add_suppression("InnoDB: \\(Lock wait timeout\\) while getting next doc id for table `test`.`t1`");
|
||||||
|
CREATE TABLE t1(f1 CHAR(100), f2 INT, fulltext(f1))ENGINE=InnoDB;
|
||||||
|
INSERT INTO t1 VALUES("mariadb", 1), ("innodb", 1);
|
||||||
|
# restart
|
||||||
|
SET DEBUG_SYNC='innodb_rollback_after_fts_lock SIGNAL insert_dml WAIT_FOR ddl_continue';
|
||||||
|
ALTER TABLE t1 ADD UNIQUE INDEX(f2);
|
||||||
|
connect con1,localhost,root,,,;
|
||||||
|
SET DEBUG_SYNC='now WAIT_FOR insert_dml';
|
||||||
|
SET DEBUG_SYNC='fts_cmp_set_sync_doc_id_retry SIGNAL ddl_continue WAIT_FOR dml_finish';
|
||||||
|
INSERT INTO t1 VALUES("index", 2);
|
||||||
|
connection default;
|
||||||
|
ERROR 23000: Duplicate entry '1' for key 'f2'
|
||||||
|
SET DEBUG_SYNC="now SIGNAL dml_finish";
|
||||||
|
connection con1;
|
||||||
|
SHOW CREATE TABLE t1;
|
||||||
|
Table Create Table
|
||||||
|
t1 CREATE TABLE `t1` (
|
||||||
|
`f1` char(100) DEFAULT NULL,
|
||||||
|
`f2` int(11) DEFAULT NULL,
|
||||||
|
FULLTEXT KEY `f1` (`f1`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci
|
||||||
|
connection default;
|
||||||
|
disconnect con1;
|
||||||
|
DROP TABLE t1;
|
||||||
|
set DEBUG_SYNC=RESET;
|
||||||
|
@ -129,8 +129,9 @@ test
|
|||||||
select * from t1 where a like "te_t";
|
select * from t1 where a like "te_t";
|
||||||
a
|
a
|
||||||
test
|
test
|
||||||
select * from t1 where match a against ("te*" in boolean mode)+0;
|
select * from t1 where match a against ("te*" in boolean mode);
|
||||||
a
|
a
|
||||||
|
test
|
||||||
drop table t1;
|
drop table t1;
|
||||||
#
|
#
|
||||||
# Bug #49734: Crash on EXPLAIN EXTENDED UNION ... ORDER BY
|
# Bug #49734: Crash on EXPLAIN EXTENDED UNION ... ORDER BY
|
||||||
|
@ -48,5 +48,33 @@ connection con1;
|
|||||||
reap;
|
reap;
|
||||||
drop table t1, t2;
|
drop table t1, t2;
|
||||||
connection default;
|
connection default;
|
||||||
set DEBUG_SYNC=RESET;
|
|
||||||
SET @@GLOBAL.debug_dbug = @saved_dbug;
|
SET @@GLOBAL.debug_dbug = @saved_dbug;
|
||||||
|
disconnect con1;
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # MDEV-25984 Assertion `max_doc_id > 0' failed in fts_init_doc_id()
|
||||||
|
--echo #
|
||||||
|
call mtr.add_suppression("InnoDB: \\(Lock wait timeout\\) while getting next doc id for table `test`.`t1`");
|
||||||
|
|
||||||
|
CREATE TABLE t1(f1 CHAR(100), f2 INT, fulltext(f1))ENGINE=InnoDB;
|
||||||
|
INSERT INTO t1 VALUES("mariadb", 1), ("innodb", 1);
|
||||||
|
--source include/restart_mysqld.inc
|
||||||
|
SET DEBUG_SYNC='innodb_rollback_after_fts_lock SIGNAL insert_dml WAIT_FOR ddl_continue';
|
||||||
|
SEND ALTER TABLE t1 ADD UNIQUE INDEX(f2);
|
||||||
|
|
||||||
|
connect(con1,localhost,root,,,);
|
||||||
|
SET DEBUG_SYNC='now WAIT_FOR insert_dml';
|
||||||
|
SET DEBUG_SYNC='fts_cmp_set_sync_doc_id_retry SIGNAL ddl_continue WAIT_FOR dml_finish';
|
||||||
|
send INSERT INTO t1 VALUES("index", 2);
|
||||||
|
|
||||||
|
connection default;
|
||||||
|
--error ER_DUP_ENTRY
|
||||||
|
reap;
|
||||||
|
SET DEBUG_SYNC="now SIGNAL dml_finish";
|
||||||
|
connection con1;
|
||||||
|
reap;
|
||||||
|
SHOW CREATE TABLE t1;
|
||||||
|
connection default;
|
||||||
|
disconnect con1;
|
||||||
|
DROP TABLE t1;
|
||||||
|
set DEBUG_SYNC=RESET;
|
||||||
|
@ -152,10 +152,7 @@ insert into t1 values ("a"),("abc"),("abcd"),("hello"),("test");
|
|||||||
select * from t1 where a like "abc%";
|
select * from t1 where a like "abc%";
|
||||||
select * from t1 where a like "test%";
|
select * from t1 where a like "test%";
|
||||||
select * from t1 where a like "te_t";
|
select * from t1 where a like "te_t";
|
||||||
# InnoDB_FTS: we don't support the postfix "+0"
|
select * from t1 where match a against ("te*" in boolean mode);
|
||||||
# Work around MDEV-29871 (FIXME: remove this)
|
|
||||||
--echo select * from t1 where match a against ("te*" in boolean mode)+0;
|
|
||||||
--echo a
|
|
||||||
drop table t1;
|
drop table t1;
|
||||||
|
|
||||||
|
|
||||||
|
@ -2575,7 +2575,6 @@ fts_cmp_set_sync_doc_id(
|
|||||||
que_t* graph = NULL;
|
que_t* graph = NULL;
|
||||||
fts_cache_t* cache = table->fts->cache;
|
fts_cache_t* cache = table->fts->cache;
|
||||||
char table_name[MAX_FULL_NAME_LEN];
|
char table_name[MAX_FULL_NAME_LEN];
|
||||||
retry:
|
|
||||||
ut_a(table->fts->doc_col != ULINT_UNDEFINED);
|
ut_a(table->fts->doc_col != ULINT_UNDEFINED);
|
||||||
|
|
||||||
fts_table.suffix = "CONFIG";
|
fts_table.suffix = "CONFIG";
|
||||||
@ -2584,6 +2583,7 @@ retry:
|
|||||||
fts_table.table = table;
|
fts_table.table = table;
|
||||||
|
|
||||||
trx= trx_create();
|
trx= trx_create();
|
||||||
|
retry:
|
||||||
trx_start_internal(trx);
|
trx_start_internal(trx);
|
||||||
|
|
||||||
trx->op_info = "update the next FTS document id";
|
trx->op_info = "update the next FTS document id";
|
||||||
@ -2663,7 +2663,8 @@ func_exit:
|
|||||||
"for table " << table->name;
|
"for table " << table->name;
|
||||||
fts_sql_rollback(trx);
|
fts_sql_rollback(trx);
|
||||||
|
|
||||||
if (error == DB_DEADLOCK) {
|
if (error == DB_DEADLOCK || error == DB_LOCK_WAIT_TIMEOUT) {
|
||||||
|
DEBUG_SYNC_C("fts_cmp_set_sync_doc_id_retry");
|
||||||
std::this_thread::sleep_for(FTS_DEADLOCK_RETRY_WAIT);
|
std::this_thread::sleep_for(FTS_DEADLOCK_RETRY_WAIT);
|
||||||
goto retry;
|
goto retry;
|
||||||
}
|
}
|
||||||
|
@ -9035,6 +9035,7 @@ inline bool rollback_inplace_alter_table(Alter_inplace_info *ha_alter_info,
|
|||||||
ut_a(!lock_table_for_trx(dict_sys.sys_fields, ctx->trx, LOCK_X));
|
ut_a(!lock_table_for_trx(dict_sys.sys_fields, ctx->trx, LOCK_X));
|
||||||
}
|
}
|
||||||
innodb_lock_wait_timeout= save_timeout;
|
innodb_lock_wait_timeout= save_timeout;
|
||||||
|
DEBUG_SYNC_C("innodb_rollback_after_fts_lock");
|
||||||
row_mysql_lock_data_dictionary(ctx->trx);
|
row_mysql_lock_data_dictionary(ctx->trx);
|
||||||
ctx->rollback_instant();
|
ctx->rollback_instant();
|
||||||
innobase_rollback_sec_index(ctx->old_table, table,
|
innobase_rollback_sec_index(ctx->old_table, table,
|
||||||
|
@ -891,8 +891,8 @@ public:
|
|||||||
|
|
||||||
/** Cancel a waiting lock request.
|
/** Cancel a waiting lock request.
|
||||||
@tparam check_victim whether to check for DB_DEADLOCK
|
@tparam check_victim whether to check for DB_DEADLOCK
|
||||||
@param lock waiting lock request
|
|
||||||
@param trx active transaction
|
@param trx active transaction
|
||||||
|
@param lock waiting lock request
|
||||||
@retval DB_SUCCESS if no lock existed
|
@retval DB_SUCCESS if no lock existed
|
||||||
@retval DB_DEADLOCK if trx->lock.was_chosen_as_deadlock_victim was set
|
@retval DB_DEADLOCK if trx->lock.was_chosen_as_deadlock_victim was set
|
||||||
@retval DB_LOCK_WAIT if the lock was canceled */
|
@retval DB_LOCK_WAIT if the lock was canceled */
|
||||||
|
@ -65,53 +65,44 @@ struct alignas(CPU_LEVEL1_DCACHE_LINESIZE) trx_rseg_t
|
|||||||
/** length of the TRX_RSEG_HISTORY list (number of transactions) */
|
/** length of the TRX_RSEG_HISTORY list (number of transactions) */
|
||||||
uint32_t history_size;
|
uint32_t history_size;
|
||||||
|
|
||||||
|
/** Last known transaction that has not been purged yet,
|
||||||
|
or 0 if everything has been purged. */
|
||||||
|
trx_id_t needs_purge;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/** Reference counter to track rseg allocated transactions,
|
/** Reference counter to track is_persistent() transactions,
|
||||||
with SKIP and NEEDS_PURGE flags. */
|
with SKIP flag. */
|
||||||
std::atomic<uint32_t> ref;
|
std::atomic<uint32_t> ref;
|
||||||
|
|
||||||
/** Whether undo tablespace truncation is pending */
|
/** Whether undo tablespace truncation is pending */
|
||||||
static constexpr uint32_t SKIP= 1;
|
static constexpr uint32_t SKIP= 1;
|
||||||
/** Whether the log segment needs purge */
|
|
||||||
static constexpr uint32_t NEEDS_PURGE= 2;
|
|
||||||
/** Transaction reference count multiplier */
|
/** Transaction reference count multiplier */
|
||||||
static constexpr uint32_t REF= 4;
|
static constexpr uint32_t REF= 2;
|
||||||
|
|
||||||
uint32_t ref_load() const { return ref.load(std::memory_order_relaxed); }
|
uint32_t ref_load() const { return ref.load(std::memory_order_relaxed); }
|
||||||
|
|
||||||
/** Set a bit in ref */
|
/** Set the SKIP bit */
|
||||||
template<bool needs_purge> void ref_set()
|
void ref_set_skip()
|
||||||
{
|
{
|
||||||
static_assert(SKIP == 1U << 0, "compatibility");
|
static_assert(SKIP == 1U, "compatibility");
|
||||||
static_assert(NEEDS_PURGE == 1U << 1, "compatibility");
|
|
||||||
#if defined __GNUC__ && (defined __i386__ || defined __x86_64__)
|
#if defined __GNUC__ && (defined __i386__ || defined __x86_64__)
|
||||||
if (needs_purge)
|
|
||||||
__asm__ __volatile__("lock btsl $1, %0" : "+m" (ref));
|
|
||||||
else
|
|
||||||
__asm__ __volatile__("lock btsl $0, %0" : "+m" (ref));
|
__asm__ __volatile__("lock btsl $0, %0" : "+m" (ref));
|
||||||
#elif defined _MSC_VER && (defined _M_IX86 || defined _M_X64)
|
#elif defined _MSC_VER && (defined _M_IX86 || defined _M_X64)
|
||||||
_interlockedbittestandset(reinterpret_cast<volatile long*>(&ref),
|
_interlockedbittestandset(reinterpret_cast<volatile long*>(&ref), 0);
|
||||||
needs_purge);
|
|
||||||
#else
|
#else
|
||||||
ref.fetch_or(needs_purge ? NEEDS_PURGE : SKIP, std::memory_order_relaxed);
|
ref.fetch_or(SKIP, std::memory_order_relaxed);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
/** Clear a bit in ref */
|
/** Clear a bit in ref */
|
||||||
template<bool needs_purge> void ref_reset()
|
void ref_reset_skip()
|
||||||
{
|
{
|
||||||
static_assert(SKIP == 1U << 0, "compatibility");
|
static_assert(SKIP == 1U, "compatibility");
|
||||||
static_assert(NEEDS_PURGE == 1U << 1, "compatibility");
|
|
||||||
#if defined __GNUC__ && (defined __i386__ || defined __x86_64__)
|
#if defined __GNUC__ && (defined __i386__ || defined __x86_64__)
|
||||||
if (needs_purge)
|
|
||||||
__asm__ __volatile__("lock btrl $1, %0" : "+m" (ref));
|
|
||||||
else
|
|
||||||
__asm__ __volatile__("lock btrl $0, %0" : "+m" (ref));
|
__asm__ __volatile__("lock btrl $0, %0" : "+m" (ref));
|
||||||
#elif defined _MSC_VER && (defined _M_IX86 || defined _M_X64)
|
#elif defined _MSC_VER && (defined _M_IX86 || defined _M_X64)
|
||||||
_interlockedbittestandreset(reinterpret_cast<volatile long*>(&ref),
|
_interlockedbittestandreset(reinterpret_cast<volatile long*>(&ref), 0);
|
||||||
needs_purge);
|
|
||||||
#else
|
#else
|
||||||
ref.fetch_and(needs_purge ? ~NEEDS_PURGE : ~SKIP,
|
ref.fetch_and(~SKIP, std::memory_order_relaxed);
|
||||||
std::memory_order_relaxed);
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -125,26 +116,20 @@ public:
|
|||||||
void destroy();
|
void destroy();
|
||||||
|
|
||||||
/** Note that undo tablespace truncation was started. */
|
/** Note that undo tablespace truncation was started. */
|
||||||
void set_skip_allocation() { ut_ad(is_persistent()); ref_set<false>(); }
|
void set_skip_allocation() { ut_ad(is_persistent()); ref_set_skip(); }
|
||||||
/** Note that undo tablespace truncation was completed. */
|
/** Note that undo tablespace truncation was completed. */
|
||||||
void clear_skip_allocation()
|
void clear_skip_allocation()
|
||||||
{
|
{
|
||||||
ut_ad(is_persistent());
|
ut_ad(is_persistent());
|
||||||
#if defined DBUG_OFF
|
#if defined DBUG_OFF
|
||||||
ref_reset<false>();
|
ref_reset_skip();
|
||||||
#else
|
#else
|
||||||
ut_d(auto r=) ref.fetch_and(~SKIP, std::memory_order_relaxed);
|
ut_d(auto r=) ref.fetch_and(~SKIP, std::memory_order_relaxed);
|
||||||
ut_ad(r == SKIP);
|
ut_ad(r == SKIP);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
/** Note that the rollback segment requires purge. */
|
|
||||||
void set_needs_purge() { ref_set<true>(); }
|
|
||||||
/** Note that the rollback segment will not require purge. */
|
|
||||||
void clear_needs_purge() { ref_reset<true>(); }
|
|
||||||
/** @return whether the segment is marked for undo truncation */
|
/** @return whether the segment is marked for undo truncation */
|
||||||
bool skip_allocation() const { return ref_load() & SKIP; }
|
bool skip_allocation() const { return ref_load() & SKIP; }
|
||||||
/** @return whether the segment needs purge */
|
|
||||||
bool needs_purge() const { return ref_load() & NEEDS_PURGE; }
|
|
||||||
/** Increment the reference count */
|
/** Increment the reference count */
|
||||||
void acquire()
|
void acquire()
|
||||||
{ ut_d(auto r=) ref.fetch_add(REF); ut_ad(!(r & SKIP)); }
|
{ ut_d(auto r=) ref.fetch_add(REF); ut_ad(!(r & SKIP)); }
|
||||||
|
@ -246,12 +246,10 @@ trx_undo_free_at_shutdown(trx_t *trx);
|
|||||||
@param[in,out] rseg rollback segment
|
@param[in,out] rseg rollback segment
|
||||||
@param[in] id rollback segment slot
|
@param[in] id rollback segment slot
|
||||||
@param[in] page_no undo log segment page number
|
@param[in] page_no undo log segment page number
|
||||||
@param[in,out] max_trx_id the largest observed transaction ID
|
|
||||||
@return the undo log
|
@return the undo log
|
||||||
@retval nullptr on error */
|
@retval nullptr on error */
|
||||||
trx_undo_t *
|
trx_undo_t *
|
||||||
trx_undo_mem_create_at_db_start(trx_rseg_t *rseg, ulint id, uint32_t page_no,
|
trx_undo_mem_create_at_db_start(trx_rseg_t *rseg, ulint id, uint32_t page_no);
|
||||||
trx_id_t &max_trx_id);
|
|
||||||
|
|
||||||
#endif /* !UNIV_INNOCHECKSUM */
|
#endif /* !UNIV_INNOCHECKSUM */
|
||||||
|
|
||||||
@ -493,6 +491,8 @@ or 0 if the transaction has not been committed */
|
|||||||
/** Before MariaDB 10.3.1, when purge did not reset DB_TRX_ID of
|
/** Before MariaDB 10.3.1, when purge did not reset DB_TRX_ID of
|
||||||
surviving user records, this used to be called TRX_UNDO_DEL_MARKS.
|
surviving user records, this used to be called TRX_UNDO_DEL_MARKS.
|
||||||
|
|
||||||
|
This field is redundant; it is only being read by some debug assertions.
|
||||||
|
|
||||||
The value 1 indicates that purge needs to process the undo log segment.
|
The value 1 indicates that purge needs to process the undo log segment.
|
||||||
The value 0 indicates that all of it has been processed, and
|
The value 0 indicates that all of it has been processed, and
|
||||||
trx_purge_free_segment() has been invoked, so the log is not safe to access.
|
trx_purge_free_segment() has been invoked, so the log is not safe to access.
|
||||||
|
@ -46,12 +46,12 @@ Created 5/7/1996 Heikki Tuuri
|
|||||||
#include "srv0mon.h"
|
#include "srv0mon.h"
|
||||||
#include "que0que.h"
|
#include "que0que.h"
|
||||||
#include "scope.h"
|
#include "scope.h"
|
||||||
|
#include <debug_sync.h>
|
||||||
|
|
||||||
#include <set>
|
#include <set>
|
||||||
|
|
||||||
#ifdef WITH_WSREP
|
#ifdef WITH_WSREP
|
||||||
#include <mysql/service_wsrep.h>
|
#include <mysql/service_wsrep.h>
|
||||||
#include <debug_sync.h>
|
|
||||||
#endif /* WITH_WSREP */
|
#endif /* WITH_WSREP */
|
||||||
|
|
||||||
/** The value of innodb_deadlock_detect */
|
/** The value of innodb_deadlock_detect */
|
||||||
@ -1882,6 +1882,7 @@ check_trx_error:
|
|||||||
if (row_lock_wait)
|
if (row_lock_wait)
|
||||||
lock_sys.wait_resume(trx->mysql_thd, suspend_time, my_hrtime_coarse());
|
lock_sys.wait_resume(trx->mysql_thd, suspend_time, my_hrtime_coarse());
|
||||||
|
|
||||||
|
/* Cache trx->lock.wait_lock to avoid unnecessary atomic variable load */
|
||||||
if (lock_t *lock= trx->lock.wait_lock)
|
if (lock_t *lock= trx->lock.wait_lock)
|
||||||
{
|
{
|
||||||
lock_sys_t::cancel<false>(trx, lock);
|
lock_sys_t::cancel<false>(trx, lock);
|
||||||
@ -1905,6 +1906,12 @@ void lock_wait_end(trx_t *trx)
|
|||||||
ut_d(const auto state= trx->state);
|
ut_d(const auto state= trx->state);
|
||||||
ut_ad(state == TRX_STATE_COMMITTED_IN_MEMORY || state == TRX_STATE_ACTIVE ||
|
ut_ad(state == TRX_STATE_COMMITTED_IN_MEMORY || state == TRX_STATE_ACTIVE ||
|
||||||
state == TRX_STATE_PREPARED);
|
state == TRX_STATE_PREPARED);
|
||||||
|
/* lock_wait() checks trx->lock.was_chosen_as_deadlock_victim flag before
|
||||||
|
requesting lock_sys.wait_mutex, and if the flag is set, it returns error,
|
||||||
|
what causes transaction rollback, which can reset trx->lock.wait_thr before
|
||||||
|
deadlock resolution starts cancelling victim's waiting lock. That's why we
|
||||||
|
don't check trx->lock.wait_thr here if the function was called from deadlock
|
||||||
|
resolution function. */
|
||||||
ut_ad(from_deadlock || trx->lock.wait_thr);
|
ut_ad(from_deadlock || trx->lock.wait_thr);
|
||||||
|
|
||||||
if (trx->lock.was_chosen_as_deadlock_victim)
|
if (trx->lock.was_chosen_as_deadlock_victim)
|
||||||
@ -3193,6 +3200,8 @@ lock_rec_store_on_page_infimum(
|
|||||||
|
|
||||||
ut_ad(block->page.frame == page_align(rec));
|
ut_ad(block->page.frame == page_align(rec));
|
||||||
const page_id_t id{block->page.id()};
|
const page_id_t id{block->page.id()};
|
||||||
|
ut_d(SCOPE_EXIT(
|
||||||
|
[]() { DEBUG_SYNC_C("lock_rec_store_on_page_infimum_end"); }));
|
||||||
|
|
||||||
LockGuard g{lock_sys.rec_hash, id};
|
LockGuard g{lock_sys.rec_hash, id};
|
||||||
lock_rec_move(g.cell(), *block, id, g.cell(), id,
|
lock_rec_move(g.cell(), *block, id, g.cell(), id,
|
||||||
@ -5770,17 +5779,30 @@ void lock_sys_t::cancel_lock_wait_for_trx(trx_t *trx)
|
|||||||
|
|
||||||
/** Cancel a waiting lock request.
|
/** Cancel a waiting lock request.
|
||||||
@tparam check_victim whether to check for DB_DEADLOCK
|
@tparam check_victim whether to check for DB_DEADLOCK
|
||||||
@param lock waiting lock request
|
|
||||||
@param trx active transaction
|
@param trx active transaction
|
||||||
|
@param lock waiting lock request
|
||||||
@retval DB_SUCCESS if no lock existed
|
@retval DB_SUCCESS if no lock existed
|
||||||
@retval DB_DEADLOCK if trx->lock.was_chosen_as_deadlock_victim was set
|
@retval DB_DEADLOCK if trx->lock.was_chosen_as_deadlock_victim was set
|
||||||
@retval DB_LOCK_WAIT if the lock was canceled */
|
@retval DB_LOCK_WAIT if the lock was canceled */
|
||||||
template<bool check_victim>
|
template<bool check_victim>
|
||||||
dberr_t lock_sys_t::cancel(trx_t *trx, lock_t *lock)
|
dberr_t lock_sys_t::cancel(trx_t *trx, lock_t *lock)
|
||||||
{
|
{
|
||||||
|
DEBUG_SYNC_C("lock_sys_t_cancel_enter");
|
||||||
mysql_mutex_assert_owner(&lock_sys.wait_mutex);
|
mysql_mutex_assert_owner(&lock_sys.wait_mutex);
|
||||||
ut_ad(trx->lock.wait_lock == lock);
|
|
||||||
ut_ad(trx->state == TRX_STATE_ACTIVE);
|
ut_ad(trx->state == TRX_STATE_ACTIVE);
|
||||||
|
/* trx->lock.wait_lock may be changed by other threads as long as
|
||||||
|
we are not holding lock_sys.latch.
|
||||||
|
|
||||||
|
So, trx->lock.wait_lock==lock does not necessarily hold, but both
|
||||||
|
pointers should be valid, because other threads cannot assign
|
||||||
|
trx->lock.wait_lock=nullptr (or invalidate *lock) while we are
|
||||||
|
holding lock_sys.wait_mutex. Also, the type of trx->lock.wait_lock
|
||||||
|
(record or table lock) cannot be changed by other threads. So, it is
|
||||||
|
safe to call lock->is_table() while not holding lock_sys.latch. If
|
||||||
|
we have to release and reacquire lock_sys.wait_mutex, we must reread
|
||||||
|
trx->lock.wait_lock. We must also reread trx->lock.wait_lock after
|
||||||
|
lock_sys.latch acquiring, as it can be changed to not-null in lock moving
|
||||||
|
functions even if we hold lock_sys.wait_mutex. */
|
||||||
dberr_t err= DB_SUCCESS;
|
dberr_t err= DB_SUCCESS;
|
||||||
/* This would be too large for a memory transaction, except in the
|
/* This would be too large for a memory transaction, except in the
|
||||||
DB_DEADLOCK case, which was already tested in lock_trx_handle_wait(). */
|
DB_DEADLOCK case, which was already tested in lock_trx_handle_wait(). */
|
||||||
@ -5802,6 +5824,15 @@ dberr_t lock_sys_t::cancel(trx_t *trx, lock_t *lock)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
/* This function is invoked from the thread which executes the
|
||||||
|
transaction. Table locks are requested before record locks. Some other
|
||||||
|
transaction can't change trx->lock.wait_lock from table to record for the
|
||||||
|
current transaction at this point, because the current transaction has not
|
||||||
|
requested record locks yet. There is no need to move any table locks by
|
||||||
|
other threads. And trx->lock.wait_lock can't be set to null while we are
|
||||||
|
holding lock_sys.wait_mutex. That's why there is no need to reload
|
||||||
|
trx->lock.wait_lock here. */
|
||||||
|
ut_ad(lock == trx->lock.wait_lock);
|
||||||
resolve_table_lock:
|
resolve_table_lock:
|
||||||
dict_table_t *table= lock->un_member.tab_lock.table;
|
dict_table_t *table= lock->un_member.tab_lock.table;
|
||||||
if (!table->lock_mutex_trylock())
|
if (!table->lock_mutex_trylock())
|
||||||
@ -5812,6 +5843,7 @@ resolve_table_lock:
|
|||||||
mysql_mutex_unlock(&lock_sys.wait_mutex);
|
mysql_mutex_unlock(&lock_sys.wait_mutex);
|
||||||
table->lock_mutex_lock();
|
table->lock_mutex_lock();
|
||||||
mysql_mutex_lock(&lock_sys.wait_mutex);
|
mysql_mutex_lock(&lock_sys.wait_mutex);
|
||||||
|
/* Cache trx->lock.wait_lock under the corresponding latches. */
|
||||||
lock= trx->lock.wait_lock;
|
lock= trx->lock.wait_lock;
|
||||||
if (!lock)
|
if (!lock)
|
||||||
goto retreat;
|
goto retreat;
|
||||||
@ -5821,6 +5853,10 @@ resolve_table_lock:
|
|||||||
goto retreat;
|
goto retreat;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
/* Cache trx->lock.wait_lock under the corresponding latches if
|
||||||
|
it was not cached yet */
|
||||||
|
lock= trx->lock.wait_lock;
|
||||||
if (lock->is_waiting())
|
if (lock->is_waiting())
|
||||||
lock_cancel_waiting_and_release(lock);
|
lock_cancel_waiting_and_release(lock);
|
||||||
/* Even if lock->is_waiting() did not hold above, we must return
|
/* Even if lock->is_waiting() did not hold above, we must return
|
||||||
@ -5844,6 +5880,7 @@ retreat:
|
|||||||
mysql_mutex_unlock(&lock_sys.wait_mutex);
|
mysql_mutex_unlock(&lock_sys.wait_mutex);
|
||||||
lock_sys.wr_lock(SRW_LOCK_CALL);
|
lock_sys.wr_lock(SRW_LOCK_CALL);
|
||||||
mysql_mutex_lock(&lock_sys.wait_mutex);
|
mysql_mutex_lock(&lock_sys.wait_mutex);
|
||||||
|
/* Cache trx->lock.wait_lock under the corresponding latches. */
|
||||||
lock= trx->lock.wait_lock;
|
lock= trx->lock.wait_lock;
|
||||||
/* Even if waiting lock was cancelled while lock_sys.wait_mutex was
|
/* Even if waiting lock was cancelled while lock_sys.wait_mutex was
|
||||||
unlocked, we need to return deadlock error if transaction was chosen
|
unlocked, we need to return deadlock error if transaction was chosen
|
||||||
@ -5855,6 +5892,9 @@ retreat:
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
/* Cache trx->lock.wait_lock under the corresponding latches if
|
||||||
|
it was not cached yet */
|
||||||
|
lock= trx->lock.wait_lock;
|
||||||
resolve_record_lock:
|
resolve_record_lock:
|
||||||
if (lock->is_waiting())
|
if (lock->is_waiting())
|
||||||
lock_cancel_waiting_and_release(lock);
|
lock_cancel_waiting_and_release(lock);
|
||||||
@ -5876,6 +5916,7 @@ resolve_record_lock:
|
|||||||
void lock_sys_t::cancel(trx_t *trx)
|
void lock_sys_t::cancel(trx_t *trx)
|
||||||
{
|
{
|
||||||
mysql_mutex_lock(&lock_sys.wait_mutex);
|
mysql_mutex_lock(&lock_sys.wait_mutex);
|
||||||
|
/* Cache trx->lock.wait_lock to avoid unnecessary atomic variable load */
|
||||||
if (lock_t *lock= trx->lock.wait_lock)
|
if (lock_t *lock= trx->lock.wait_lock)
|
||||||
{
|
{
|
||||||
/* Dictionary transactions must be immune to KILL, because they
|
/* Dictionary transactions must be immune to KILL, because they
|
||||||
@ -5943,6 +5984,7 @@ dberr_t lock_trx_handle_wait(trx_t *trx)
|
|||||||
mysql_mutex_lock(&lock_sys.wait_mutex);
|
mysql_mutex_lock(&lock_sys.wait_mutex);
|
||||||
if (trx->lock.was_chosen_as_deadlock_victim)
|
if (trx->lock.was_chosen_as_deadlock_victim)
|
||||||
err= DB_DEADLOCK;
|
err= DB_DEADLOCK;
|
||||||
|
/* Cache trx->lock.wait_lock to avoid unnecessary atomic variable load */
|
||||||
else if (lock_t *wait_lock= trx->lock.wait_lock)
|
else if (lock_t *wait_lock= trx->lock.wait_lock)
|
||||||
err= lock_sys_t::cancel<true>(trx, wait_lock);
|
err= lock_sys_t::cancel<true>(trx, wait_lock);
|
||||||
lock_sys.deadlock_check();
|
lock_sys.deadlock_check();
|
||||||
|
@ -263,6 +263,7 @@ trx_purge_add_undo_to_history(const trx_t* trx, trx_undo_t*& undo, mtr_t* mtr)
|
|||||||
+ undo->hdr_offset;
|
+ undo->hdr_offset;
|
||||||
|
|
||||||
ut_ad(mach_read_from_2(undo_header + TRX_UNDO_NEEDS_PURGE) <= 1);
|
ut_ad(mach_read_from_2(undo_header + TRX_UNDO_NEEDS_PURGE) <= 1);
|
||||||
|
ut_ad(rseg->needs_purge > trx->id);
|
||||||
|
|
||||||
if (UNIV_UNLIKELY(mach_read_from_4(TRX_RSEG + TRX_RSEG_FORMAT
|
if (UNIV_UNLIKELY(mach_read_from_4(TRX_RSEG + TRX_RSEG_FORMAT
|
||||||
+ rseg_header->page.frame))) {
|
+ rseg_header->page.frame))) {
|
||||||
@ -356,7 +357,6 @@ trx_purge_add_undo_to_history(const trx_t* trx, trx_undo_t*& undo, mtr_t* mtr)
|
|||||||
rseg->last_page_no = undo->hdr_page_no;
|
rseg->last_page_no = undo->hdr_page_no;
|
||||||
rseg->set_last_commit(undo->hdr_offset,
|
rseg->set_last_commit(undo->hdr_offset,
|
||||||
trx->rw_trx_hash_element->no);
|
trx->rw_trx_hash_element->no);
|
||||||
rseg->set_needs_purge();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
rseg->history_size++;
|
rseg->history_size++;
|
||||||
@ -387,24 +387,21 @@ static dberr_t trx_purge_remove_log_hdr(buf_block_t *rseg, buf_block_t* log,
|
|||||||
|
|
||||||
MY_ATTRIBUTE((nonnull, warn_unused_result))
|
MY_ATTRIBUTE((nonnull, warn_unused_result))
|
||||||
/** Free an undo log segment, and remove the header from the history list.
|
/** Free an undo log segment, and remove the header from the history list.
|
||||||
|
@param[in,out] mtr mini-transaction
|
||||||
@param[in,out] rseg rollback segment
|
@param[in,out] rseg rollback segment
|
||||||
@param[in] hdr_addr file address of log_hdr
|
@param[in] hdr_addr file address of log_hdr
|
||||||
@return error code */
|
@return error code */
|
||||||
static dberr_t trx_purge_free_segment(trx_rseg_t *rseg, fil_addr_t hdr_addr)
|
static dberr_t
|
||||||
|
trx_purge_free_segment(mtr_t &mtr, trx_rseg_t* rseg, fil_addr_t hdr_addr)
|
||||||
{
|
{
|
||||||
const page_id_t hdr_page_id{rseg->space->id, hdr_addr.page};
|
mtr.commit();
|
||||||
mtr_t mtr;
|
|
||||||
mtr.start();
|
mtr.start();
|
||||||
|
|
||||||
/* We only need the latch to maintain rseg->curr_size. To follow the
|
const page_id_t hdr_page_id{rseg->space->id, hdr_addr.page};
|
||||||
latching order, we must acquire it before acquiring any related
|
|
||||||
page latch. */
|
|
||||||
rseg->latch.wr_lock(SRW_LOCK_CALL);
|
|
||||||
|
|
||||||
dberr_t err;
|
dberr_t err;
|
||||||
buf_block_t *rseg_hdr= rseg->get(&mtr, &err);
|
buf_block_t *rseg_hdr= rseg->get(&mtr, &err);
|
||||||
if (!rseg_hdr)
|
if (!rseg_hdr)
|
||||||
goto func_exit;
|
return err;
|
||||||
if (buf_block_t *block= buf_page_get_gen(hdr_page_id, 0, RW_X_LATCH,
|
if (buf_block_t *block= buf_page_get_gen(hdr_page_id, 0, RW_X_LATCH,
|
||||||
nullptr, BUF_GET_POSSIBLY_FREED,
|
nullptr, BUF_GET_POSSIBLY_FREED,
|
||||||
&mtr, &err))
|
&mtr, &err))
|
||||||
@ -419,12 +416,10 @@ static dberr_t trx_purge_free_segment(trx_rseg_t *rseg, fil_addr_t hdr_addr)
|
|||||||
while (!fseg_free_step_not_header(TRX_UNDO_SEG_HDR + TRX_UNDO_FSEG_HEADER +
|
while (!fseg_free_step_not_header(TRX_UNDO_SEG_HDR + TRX_UNDO_FSEG_HEADER +
|
||||||
block->page.frame, &mtr))
|
block->page.frame, &mtr))
|
||||||
{
|
{
|
||||||
rseg->latch.wr_unlock();
|
|
||||||
rseg_hdr->fix();
|
rseg_hdr->fix();
|
||||||
block->fix();
|
block->fix();
|
||||||
mtr.commit();
|
mtr.commit();
|
||||||
mtr.start();
|
mtr.start();
|
||||||
rseg->latch.wr_lock(SRW_LOCK_CALL);
|
|
||||||
rseg_hdr->page.lock.x_lock();
|
rseg_hdr->page.lock.x_lock();
|
||||||
block->page.lock.x_lock();
|
block->page.lock.x_lock();
|
||||||
mtr.memo_push(rseg_hdr, MTR_MEMO_PAGE_X_FIX);
|
mtr.memo_push(rseg_hdr, MTR_MEMO_PAGE_X_FIX);
|
||||||
@ -443,13 +438,10 @@ static dberr_t trx_purge_free_segment(trx_rseg_t *rseg, fil_addr_t hdr_addr)
|
|||||||
could become inaccessible garbage in the file space. */
|
could become inaccessible garbage in the file space. */
|
||||||
err= trx_purge_remove_log_hdr(rseg_hdr, block, hdr_addr.boffset, &mtr);
|
err= trx_purge_remove_log_hdr(rseg_hdr, block, hdr_addr.boffset, &mtr);
|
||||||
if (UNIV_UNLIKELY(err != DB_SUCCESS))
|
if (UNIV_UNLIKELY(err != DB_SUCCESS))
|
||||||
goto func_exit;
|
return err;
|
||||||
byte *hist= TRX_RSEG + TRX_RSEG_HISTORY_SIZE + rseg_hdr->page.frame;
|
byte *hist= TRX_RSEG + TRX_RSEG_HISTORY_SIZE + rseg_hdr->page.frame;
|
||||||
if (UNIV_UNLIKELY(mach_read_from_4(hist) < seg_size))
|
if (UNIV_UNLIKELY(mach_read_from_4(hist) < seg_size))
|
||||||
{
|
return DB_CORRUPTION;
|
||||||
err= DB_CORRUPTION;
|
|
||||||
goto func_exit;
|
|
||||||
}
|
|
||||||
mtr.write<4>(*rseg_hdr, hist, mach_read_from_4(hist) - seg_size);
|
mtr.write<4>(*rseg_hdr, hist, mach_read_from_4(hist) - seg_size);
|
||||||
|
|
||||||
/* Here we assume that a file segment with just the header page
|
/* Here we assume that a file segment with just the header page
|
||||||
@ -464,9 +456,6 @@ static dberr_t trx_purge_free_segment(trx_rseg_t *rseg, fil_addr_t hdr_addr)
|
|||||||
rseg->curr_size -= seg_size;
|
rseg->curr_size -= seg_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
func_exit:
|
|
||||||
rseg->latch.wr_unlock();
|
|
||||||
mtr.commit();
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -484,8 +473,6 @@ trx_purge_truncate_rseg_history(
|
|||||||
mtr_t mtr;
|
mtr_t mtr;
|
||||||
|
|
||||||
mtr.start();
|
mtr.start();
|
||||||
ut_ad(rseg.is_persistent());
|
|
||||||
rseg.latch.wr_lock(SRW_LOCK_CALL);
|
|
||||||
|
|
||||||
dberr_t err;
|
dberr_t err;
|
||||||
buf_block_t* rseg_hdr = rseg.get(&mtr, &err);
|
buf_block_t* rseg_hdr = rseg.get(&mtr, &err);
|
||||||
@ -501,7 +488,6 @@ trx_purge_truncate_rseg_history(
|
|||||||
loop:
|
loop:
|
||||||
if (hdr_addr.page == FIL_NULL) {
|
if (hdr_addr.page == FIL_NULL) {
|
||||||
func_exit:
|
func_exit:
|
||||||
rseg.latch.wr_unlock();
|
|
||||||
mtr.commit();
|
mtr.commit();
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
@ -533,38 +519,30 @@ func_exit:
|
|||||||
prev_hdr_addr.boffset = static_cast<uint16_t>(prev_hdr_addr.boffset
|
prev_hdr_addr.boffset = static_cast<uint16_t>(prev_hdr_addr.boffset
|
||||||
- TRX_UNDO_HISTORY_NODE);
|
- TRX_UNDO_HISTORY_NODE);
|
||||||
|
|
||||||
if (mach_read_from_2(TRX_UNDO_SEG_HDR + TRX_UNDO_STATE
|
if (!rseg.is_referenced()
|
||||||
|
&& rseg.needs_purge <= (purge_sys.head.trx_no
|
||||||
|
? purge_sys.head.trx_no
|
||||||
|
: purge_sys.tail.trx_no)
|
||||||
|
&& mach_read_from_2(TRX_UNDO_SEG_HDR + TRX_UNDO_STATE
|
||||||
+ block->page.frame)
|
+ block->page.frame)
|
||||||
== TRX_UNDO_TO_PURGE
|
== TRX_UNDO_TO_PURGE
|
||||||
&& !mach_read_from_2(block->page.frame + hdr_addr.boffset
|
&& !mach_read_from_2(block->page.frame + hdr_addr.boffset
|
||||||
+ TRX_UNDO_NEXT_LOG)) {
|
+ TRX_UNDO_NEXT_LOG)) {
|
||||||
|
/* We can free the whole log segment.
|
||||||
|
This will call trx_purge_remove_log_hdr(). */
|
||||||
|
err = trx_purge_free_segment(mtr, &rseg, hdr_addr);
|
||||||
|
} else {
|
||||||
|
/* Remove the log hdr from the rseg history. */
|
||||||
|
rseg.history_size--;
|
||||||
|
err = trx_purge_remove_log_hdr(rseg_hdr, block,
|
||||||
|
hdr_addr.boffset, &mtr);
|
||||||
|
}
|
||||||
|
|
||||||
/* We can free the whole log segment */
|
|
||||||
|
|
||||||
rseg.latch.wr_unlock();
|
|
||||||
mtr.commit();
|
mtr.commit();
|
||||||
|
|
||||||
/* calls the trx_purge_remove_log_hdr()
|
|
||||||
inside trx_purge_free_segment(). */
|
|
||||||
err = trx_purge_free_segment(&rseg, hdr_addr);
|
|
||||||
if (err != DB_SUCCESS) {
|
if (err != DB_SUCCESS) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
/* Remove the log hdr from the rseg history. */
|
|
||||||
err = trx_purge_remove_log_hdr(rseg_hdr, block,
|
|
||||||
hdr_addr.boffset, &mtr);
|
|
||||||
if (err != DB_SUCCESS) {
|
|
||||||
goto func_exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
rseg.history_size--;
|
|
||||||
rseg.latch.wr_unlock();
|
|
||||||
mtr.commit();
|
|
||||||
}
|
|
||||||
|
|
||||||
mtr.start();
|
mtr.start();
|
||||||
rseg.latch.wr_lock(SRW_LOCK_CALL);
|
|
||||||
|
|
||||||
hdr_addr = prev_hdr_addr;
|
hdr_addr = prev_hdr_addr;
|
||||||
|
|
||||||
@ -640,8 +618,13 @@ TRANSACTIONAL_TARGET static void trx_purge_truncate_history()
|
|||||||
dberr_t err= DB_SUCCESS;
|
dberr_t err= DB_SUCCESS;
|
||||||
for (auto &rseg : trx_sys.rseg_array)
|
for (auto &rseg : trx_sys.rseg_array)
|
||||||
if (rseg.space)
|
if (rseg.space)
|
||||||
|
{
|
||||||
|
ut_ad(rseg.is_persistent());
|
||||||
|
rseg.latch.wr_lock(SRW_LOCK_CALL);
|
||||||
if (dberr_t e= trx_purge_truncate_rseg_history(rseg, head))
|
if (dberr_t e= trx_purge_truncate_rseg_history(rseg, head))
|
||||||
err= e;
|
err= e;
|
||||||
|
rseg.latch.wr_unlock();
|
||||||
|
}
|
||||||
|
|
||||||
if (err != DB_SUCCESS || srv_undo_tablespaces_active < 2)
|
if (err != DB_SUCCESS || srv_undo_tablespaces_active < 2)
|
||||||
return;
|
return;
|
||||||
@ -693,26 +676,21 @@ TRANSACTIONAL_TARGET static void trx_purge_truncate_history()
|
|||||||
{
|
{
|
||||||
if (rseg.space != &space)
|
if (rseg.space != &space)
|
||||||
continue;
|
continue;
|
||||||
#ifdef SUX_LOCK_GENERIC
|
|
||||||
rseg.latch.rd_lock(SRW_LOCK_CALL);
|
rseg.latch.rd_lock(SRW_LOCK_CALL);
|
||||||
#else
|
|
||||||
transactional_shared_lock_guard<srw_spin_lock> g{rseg.latch};
|
|
||||||
#endif
|
|
||||||
ut_ad(rseg.skip_allocation());
|
ut_ad(rseg.skip_allocation());
|
||||||
if (rseg.is_referenced())
|
if (rseg.is_referenced() || rseg.needs_purge > head.trx_no)
|
||||||
{
|
{
|
||||||
not_free:
|
not_free:
|
||||||
#ifdef SUX_LOCK_GENERIC
|
|
||||||
rseg.latch.rd_unlock();
|
rseg.latch.rd_unlock();
|
||||||
#endif
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rseg.curr_size != 1)
|
ut_ad(UT_LIST_GET_LEN(rseg.undo_list) == 0);
|
||||||
{
|
|
||||||
/* Check if all segments are cached and safe to remove. */
|
/* Check if all segments are cached and safe to remove. */
|
||||||
ulint cached= 0;
|
ulint cached= 0;
|
||||||
for (trx_undo_t *undo= UT_LIST_GET_FIRST(rseg.undo_cached); undo;
|
|
||||||
|
for (const trx_undo_t *undo= UT_LIST_GET_FIRST(rseg.undo_cached); undo;
|
||||||
undo= UT_LIST_GET_NEXT(undo_list, undo))
|
undo= UT_LIST_GET_NEXT(undo_list, undo))
|
||||||
{
|
{
|
||||||
if (head.trx_no < undo->trx_id)
|
if (head.trx_no < undo->trx_id)
|
||||||
@ -722,14 +700,10 @@ not_free:
|
|||||||
}
|
}
|
||||||
|
|
||||||
ut_ad(rseg.curr_size > cached);
|
ut_ad(rseg.curr_size > cached);
|
||||||
|
|
||||||
if (rseg.curr_size > cached + 1)
|
if (rseg.curr_size > cached + 1)
|
||||||
goto not_free;
|
goto not_free;
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef SUX_LOCK_GENERIC
|
|
||||||
rseg.latch.rd_unlock();
|
rseg.latch.rd_unlock();
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ib::info() << "Truncating " << file->name;
|
ib::info() << "Truncating " << file->name;
|
||||||
@ -848,7 +822,9 @@ not_free:
|
|||||||
if (rseg.space != &space)
|
if (rseg.space != &space)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
dberr_t err;
|
ut_ad(!rseg.is_referenced());
|
||||||
|
ut_ad(rseg.needs_purge <= head.trx_no);
|
||||||
|
|
||||||
buf_block_t *rblock= trx_rseg_header_create(&space,
|
buf_block_t *rblock= trx_rseg_header_create(&space,
|
||||||
&rseg - trx_sys.rseg_array,
|
&rseg - trx_sys.rseg_array,
|
||||||
trx_sys.get_max_trx_id(),
|
trx_sys.get_max_trx_id(),
|
||||||
@ -883,10 +859,6 @@ not_free:
|
|||||||
log_buffer_flush_to_disk();
|
log_buffer_flush_to_disk();
|
||||||
DBUG_SUICIDE(););
|
DBUG_SUICIDE(););
|
||||||
|
|
||||||
for (auto &rseg : trx_sys.rseg_array)
|
|
||||||
if (rseg.space == &space)
|
|
||||||
rseg.clear_skip_allocation();
|
|
||||||
|
|
||||||
ib::info() << "Truncated " << file->name;
|
ib::info() << "Truncated " << file->name;
|
||||||
purge_sys.truncate.last= purge_sys.truncate.current;
|
purge_sys.truncate.last= purge_sys.truncate.current;
|
||||||
ut_ad(&space == purge_sys.truncate.current);
|
ut_ad(&space == purge_sys.truncate.current);
|
||||||
@ -946,7 +918,6 @@ static void trx_purge_rseg_get_next_history_log(
|
|||||||
/* Read the previous log header. */
|
/* Read the previous log header. */
|
||||||
mtr.start();
|
mtr.start();
|
||||||
|
|
||||||
byte needs_purge= 0;
|
|
||||||
trx_id_t trx_no= 0;
|
trx_id_t trx_no= 0;
|
||||||
|
|
||||||
if (const buf_block_t* undo_page=
|
if (const buf_block_t* undo_page=
|
||||||
@ -957,7 +928,6 @@ static void trx_purge_rseg_get_next_history_log(
|
|||||||
|
|
||||||
trx_no= mach_read_from_8(log_hdr + TRX_UNDO_TRX_NO);
|
trx_no= mach_read_from_8(log_hdr + TRX_UNDO_TRX_NO);
|
||||||
ut_ad(mach_read_from_2(log_hdr + TRX_UNDO_NEEDS_PURGE) <= 1);
|
ut_ad(mach_read_from_2(log_hdr + TRX_UNDO_NEEDS_PURGE) <= 1);
|
||||||
needs_purge= log_hdr[TRX_UNDO_NEEDS_PURGE + 1];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mtr.commit();
|
mtr.commit();
|
||||||
@ -969,11 +939,6 @@ static void trx_purge_rseg_get_next_history_log(
|
|||||||
purge_sys.rseg->last_page_no= prev_log_addr.page;
|
purge_sys.rseg->last_page_no= prev_log_addr.page;
|
||||||
purge_sys.rseg->set_last_commit(prev_log_addr.boffset, trx_no);
|
purge_sys.rseg->set_last_commit(prev_log_addr.boffset, trx_no);
|
||||||
|
|
||||||
if (needs_purge)
|
|
||||||
purge_sys.rseg->set_needs_purge();
|
|
||||||
else
|
|
||||||
purge_sys.rseg->clear_needs_purge();
|
|
||||||
|
|
||||||
/* Purge can also produce events, however these are already ordered
|
/* Purge can also produce events, however these are already ordered
|
||||||
in the rollback segment and any user generated event will be greater
|
in the rollback segment and any user generated event will be greater
|
||||||
than the events that Purge produces. ie. Purge can never produce
|
than the events that Purge produces. ie. Purge can never produce
|
||||||
@ -995,7 +960,7 @@ static void trx_purge_read_undo_rec()
|
|||||||
purge_sys.hdr_offset = purge_sys.rseg->last_offset();
|
purge_sys.hdr_offset = purge_sys.rseg->last_offset();
|
||||||
page_no = purge_sys.hdr_page_no = purge_sys.rseg->last_page_no;
|
page_no = purge_sys.hdr_page_no = purge_sys.rseg->last_page_no;
|
||||||
|
|
||||||
if (purge_sys.rseg->needs_purge()) {
|
if (purge_sys.rseg->needs_purge) {
|
||||||
mtr_t mtr;
|
mtr_t mtr;
|
||||||
mtr.start();
|
mtr.start();
|
||||||
const buf_block_t* undo_page;
|
const buf_block_t* undo_page;
|
||||||
|
@ -399,7 +399,7 @@ void trx_rseg_t::reinit(uint32_t page)
|
|||||||
}
|
}
|
||||||
|
|
||||||
ut_ad(!is_referenced());
|
ut_ad(!is_referenced());
|
||||||
clear_needs_purge();
|
needs_purge= 0;
|
||||||
last_commit_and_offset= 0;
|
last_commit_and_offset= 0;
|
||||||
last_page_no= FIL_NULL;
|
last_page_no= FIL_NULL;
|
||||||
curr_size= 1;
|
curr_size= 1;
|
||||||
@ -407,10 +407,9 @@ void trx_rseg_t::reinit(uint32_t page)
|
|||||||
|
|
||||||
/** Read the undo log lists.
|
/** Read the undo log lists.
|
||||||
@param[in,out] rseg rollback segment
|
@param[in,out] rseg rollback segment
|
||||||
@param[in,out] max_trx_id maximum observed transaction identifier
|
|
||||||
@param[in] rseg_header rollback segment header
|
@param[in] rseg_header rollback segment header
|
||||||
@return error code */
|
@return error code */
|
||||||
static dberr_t trx_undo_lists_init(trx_rseg_t *rseg, trx_id_t &max_trx_id,
|
static dberr_t trx_undo_lists_init(trx_rseg_t *rseg,
|
||||||
const buf_block_t *rseg_header)
|
const buf_block_t *rseg_header)
|
||||||
{
|
{
|
||||||
ut_ad(srv_force_recovery < SRV_FORCE_NO_UNDO_LOG_SCAN);
|
ut_ad(srv_force_recovery < SRV_FORCE_NO_UNDO_LOG_SCAN);
|
||||||
@ -420,8 +419,8 @@ static dberr_t trx_undo_lists_init(trx_rseg_t *rseg, trx_id_t &max_trx_id,
|
|||||||
uint32_t page_no= trx_rsegf_get_nth_undo(rseg_header, i);
|
uint32_t page_no= trx_rsegf_get_nth_undo(rseg_header, i);
|
||||||
if (page_no != FIL_NULL)
|
if (page_no != FIL_NULL)
|
||||||
{
|
{
|
||||||
const trx_undo_t *undo= trx_undo_mem_create_at_db_start(rseg, i, page_no,
|
const trx_undo_t *undo=
|
||||||
max_trx_id);
|
trx_undo_mem_create_at_db_start(rseg, i, page_no);
|
||||||
if (!undo)
|
if (!undo)
|
||||||
return DB_CORRUPTION;
|
return DB_CORRUPTION;
|
||||||
rseg->curr_size+= undo->size;
|
rseg->curr_size+= undo->size;
|
||||||
@ -434,11 +433,9 @@ static dberr_t trx_undo_lists_init(trx_rseg_t *rseg, trx_id_t &max_trx_id,
|
|||||||
|
|
||||||
/** Restore the state of a persistent rollback segment.
|
/** Restore the state of a persistent rollback segment.
|
||||||
@param[in,out] rseg persistent rollback segment
|
@param[in,out] rseg persistent rollback segment
|
||||||
@param[in,out] max_trx_id maximum observed transaction identifier
|
|
||||||
@param[in,out] mtr mini-transaction
|
@param[in,out] mtr mini-transaction
|
||||||
@return error code */
|
@return error code */
|
||||||
static dberr_t trx_rseg_mem_restore(trx_rseg_t *rseg, trx_id_t &max_trx_id,
|
static dberr_t trx_rseg_mem_restore(trx_rseg_t *rseg, mtr_t *mtr)
|
||||||
mtr_t *mtr)
|
|
||||||
{
|
{
|
||||||
if (!rseg->space)
|
if (!rseg->space)
|
||||||
return DB_TABLESPACE_NOT_FOUND;
|
return DB_TABLESPACE_NOT_FOUND;
|
||||||
@ -454,8 +451,8 @@ static dberr_t trx_rseg_mem_restore(trx_rseg_t *rseg, trx_id_t &max_trx_id,
|
|||||||
trx_id_t id= mach_read_from_8(TRX_RSEG + TRX_RSEG_MAX_TRX_ID +
|
trx_id_t id= mach_read_from_8(TRX_RSEG + TRX_RSEG_MAX_TRX_ID +
|
||||||
rseg_hdr->page.frame);
|
rseg_hdr->page.frame);
|
||||||
|
|
||||||
if (id > max_trx_id)
|
if (id > rseg->needs_purge)
|
||||||
max_trx_id= id;
|
rseg->needs_purge= id;
|
||||||
|
|
||||||
const byte *binlog_name=
|
const byte *binlog_name=
|
||||||
TRX_RSEG + TRX_RSEG_BINLOG_NAME + rseg_hdr->page.frame;
|
TRX_RSEG + TRX_RSEG_BINLOG_NAME + rseg_hdr->page.frame;
|
||||||
@ -491,7 +488,7 @@ static dberr_t trx_rseg_mem_restore(trx_rseg_t *rseg, trx_id_t &max_trx_id,
|
|||||||
|
|
||||||
rseg->curr_size = mach_read_from_4(TRX_RSEG + TRX_RSEG_HISTORY_SIZE +
|
rseg->curr_size = mach_read_from_4(TRX_RSEG + TRX_RSEG_HISTORY_SIZE +
|
||||||
rseg_hdr->page.frame) + 1;
|
rseg_hdr->page.frame) + 1;
|
||||||
err= trx_undo_lists_init(rseg, max_trx_id, rseg_hdr);
|
err= trx_undo_lists_init(rseg, rseg_hdr);
|
||||||
if (err != DB_SUCCESS);
|
if (err != DB_SUCCESS);
|
||||||
else if (auto len= flst_get_len(TRX_RSEG + TRX_RSEG_HISTORY +
|
else if (auto len= flst_get_len(TRX_RSEG + TRX_RSEG_HISTORY +
|
||||||
rseg_hdr->page.frame))
|
rseg_hdr->page.frame))
|
||||||
@ -512,19 +509,16 @@ static dberr_t trx_rseg_mem_restore(trx_rseg_t *rseg, trx_id_t &max_trx_id,
|
|||||||
|
|
||||||
trx_id_t id= mach_read_from_8(block->page.frame + node_addr.boffset +
|
trx_id_t id= mach_read_from_8(block->page.frame + node_addr.boffset +
|
||||||
TRX_UNDO_TRX_ID);
|
TRX_UNDO_TRX_ID);
|
||||||
if (id > max_trx_id)
|
if (id > rseg->needs_purge)
|
||||||
max_trx_id= id;
|
rseg->needs_purge= id;
|
||||||
id= mach_read_from_8(block->page.frame + node_addr.boffset +
|
id= mach_read_from_8(block->page.frame + node_addr.boffset +
|
||||||
TRX_UNDO_TRX_NO);
|
TRX_UNDO_TRX_NO);
|
||||||
if (id > max_trx_id)
|
if (id > rseg->needs_purge)
|
||||||
max_trx_id= id;
|
rseg->needs_purge= id;
|
||||||
|
|
||||||
rseg->set_last_commit(node_addr.boffset, id);
|
rseg->set_last_commit(node_addr.boffset, id);
|
||||||
unsigned purge= mach_read_from_2(block->page.frame + node_addr.boffset +
|
ut_ad(mach_read_from_2(block->page.frame + node_addr.boffset +
|
||||||
TRX_UNDO_NEEDS_PURGE);
|
TRX_UNDO_NEEDS_PURGE) <= 1);
|
||||||
ut_ad(purge <= 1);
|
|
||||||
if (purge != 0)
|
|
||||||
rseg->set_needs_purge();
|
|
||||||
|
|
||||||
if (rseg->last_page_no != FIL_NULL)
|
if (rseg->last_page_no != FIL_NULL)
|
||||||
/* There is no need to cover this operation by the purge
|
/* There is no need to cover this operation by the purge
|
||||||
@ -597,9 +591,11 @@ dberr_t trx_rseg_array_init()
|
|||||||
sys, rseg_id)),
|
sys, rseg_id)),
|
||||||
page_no);
|
page_no);
|
||||||
ut_ad(rseg.is_persistent());
|
ut_ad(rseg.is_persistent());
|
||||||
if ((err = trx_rseg_mem_restore(
|
err = trx_rseg_mem_restore(&rseg, &mtr);
|
||||||
&rseg, max_trx_id, &mtr))
|
if (rseg.needs_purge > max_trx_id) {
|
||||||
!= DB_SUCCESS) {
|
max_trx_id = rseg.needs_purge;
|
||||||
|
}
|
||||||
|
if (err != DB_SUCCESS) {
|
||||||
mtr.commit();
|
mtr.commit();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -651,6 +651,7 @@ static dberr_t trx_resurrect(trx_undo_t *undo, trx_rseg_t *rseg,
|
|||||||
uint64_t *rows_to_undo)
|
uint64_t *rows_to_undo)
|
||||||
{
|
{
|
||||||
trx_state_t state;
|
trx_state_t state;
|
||||||
|
ut_ad(rseg->needs_purge >= undo->trx_id);
|
||||||
/*
|
/*
|
||||||
This is single-threaded startup code, we do not need the
|
This is single-threaded startup code, we do not need the
|
||||||
protection of trx->mutex here.
|
protection of trx->mutex here.
|
||||||
@ -673,6 +674,7 @@ static dberr_t trx_resurrect(trx_undo_t *undo, trx_rseg_t *rseg,
|
|||||||
return DB_SUCCESS;
|
return DB_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rseg->acquire();
|
||||||
trx_t *trx= trx_create();
|
trx_t *trx= trx_create();
|
||||||
trx->state= state;
|
trx->state= state;
|
||||||
ut_d(trx->start_file= __FILE__);
|
ut_d(trx->start_file= __FILE__);
|
||||||
@ -681,12 +683,6 @@ static dberr_t trx_resurrect(trx_undo_t *undo, trx_rseg_t *rseg,
|
|||||||
trx->rsegs.m_redo.undo= undo;
|
trx->rsegs.m_redo.undo= undo;
|
||||||
trx->undo_no= undo->top_undo_no + 1;
|
trx->undo_no= undo->top_undo_no + 1;
|
||||||
trx->rsegs.m_redo.rseg= rseg;
|
trx->rsegs.m_redo.rseg= rseg;
|
||||||
/*
|
|
||||||
For transactions with active data will not have rseg size = 1
|
|
||||||
or will not qualify for purge limit criteria. So it is safe to increment
|
|
||||||
this trx_ref_count w/o mutex protection.
|
|
||||||
*/
|
|
||||||
trx->rsegs.m_redo.rseg->acquire();
|
|
||||||
trx->xid= undo->xid;
|
trx->xid= undo->xid;
|
||||||
trx->id= undo->trx_id;
|
trx->id= undo->trx_id;
|
||||||
trx->is_recovered= true;
|
trx->is_recovered= true;
|
||||||
@ -759,6 +755,7 @@ corrupted:
|
|||||||
ut_ad(trx->is_recovered);
|
ut_ad(trx->is_recovered);
|
||||||
ut_ad(trx->rsegs.m_redo.rseg == &rseg);
|
ut_ad(trx->rsegs.m_redo.rseg == &rseg);
|
||||||
ut_ad(rseg.is_referenced());
|
ut_ad(rseg.is_referenced());
|
||||||
|
ut_ad(rseg.needs_purge);
|
||||||
|
|
||||||
trx->rsegs.m_redo.undo = undo;
|
trx->rsegs.m_redo.undo = undo;
|
||||||
if (undo->top_undo_no >= trx->undo_no) {
|
if (undo->top_undo_no >= trx->undo_no) {
|
||||||
@ -794,20 +791,18 @@ corrupted:
|
|||||||
|
|
||||||
/** Assign a persistent rollback segment in a round-robin fashion,
|
/** Assign a persistent rollback segment in a round-robin fashion,
|
||||||
evenly distributed between 0 and innodb_undo_logs-1
|
evenly distributed between 0 and innodb_undo_logs-1
|
||||||
@return persistent rollback segment
|
@param trx transaction */
|
||||||
@retval NULL if innodb_read_only */
|
static void trx_assign_rseg_low(trx_t *trx)
|
||||||
static trx_rseg_t* trx_assign_rseg_low()
|
|
||||||
{
|
{
|
||||||
if (high_level_read_only) {
|
ut_ad(!trx->rsegs.m_redo.rseg);
|
||||||
ut_ad(!srv_available_undo_logs);
|
|
||||||
return(NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
ut_ad(srv_available_undo_logs == TRX_SYS_N_RSEGS);
|
ut_ad(srv_available_undo_logs == TRX_SYS_N_RSEGS);
|
||||||
|
|
||||||
/* The first slot is always assigned to the system tablespace. */
|
/* The first slot is always assigned to the system tablespace. */
|
||||||
ut_ad(trx_sys.rseg_array[0].space == fil_system.sys_space);
|
ut_ad(trx_sys.rseg_array[0].space == fil_system.sys_space);
|
||||||
|
|
||||||
|
trx_sys.register_rw(trx);
|
||||||
|
ut_ad(trx->id);
|
||||||
|
|
||||||
/* Choose a rollback segment evenly distributed between 0 and
|
/* Choose a rollback segment evenly distributed between 0 and
|
||||||
innodb_undo_logs-1 in a round-robin fashion, skipping those
|
innodb_undo_logs-1 in a round-robin fashion, skipping those
|
||||||
undo tablespaces that are scheduled for truncation. */
|
undo tablespaces that are scheduled for truncation. */
|
||||||
@ -821,7 +816,7 @@ static trx_rseg_t* trx_assign_rseg_low()
|
|||||||
bool look_for_rollover = false;
|
bool look_for_rollover = false;
|
||||||
#endif /* UNIV_DEBUG */
|
#endif /* UNIV_DEBUG */
|
||||||
|
|
||||||
bool allocated = false;
|
bool allocated;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
for (;;) {
|
for (;;) {
|
||||||
@ -871,9 +866,7 @@ static trx_rseg_t* trx_assign_rseg_low()
|
|||||||
allocated = rseg->acquire_if_available();
|
allocated = rseg->acquire_if_available();
|
||||||
} while (!allocated);
|
} while (!allocated);
|
||||||
|
|
||||||
ut_ad(rseg->is_referenced());
|
trx->rsegs.m_redo.rseg = rseg;
|
||||||
ut_ad(rseg->is_persistent());
|
|
||||||
return(rseg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Assign a rollback segment for modifying temporary tables.
|
/** Assign a rollback segment for modifying temporary tables.
|
||||||
@ -956,15 +949,11 @@ trx_start_low(
|
|||||||
|
|
||||||
if (!trx->read_only
|
if (!trx->read_only
|
||||||
&& (!trx->mysql_thd || read_write || trx->dict_operation)) {
|
&& (!trx->mysql_thd || read_write || trx->dict_operation)) {
|
||||||
|
|
||||||
/* Temporary rseg is assigned only if the transaction
|
/* Temporary rseg is assigned only if the transaction
|
||||||
updates a temporary table */
|
updates a temporary table */
|
||||||
trx->rsegs.m_redo.rseg = trx_assign_rseg_low();
|
if (!high_level_read_only) {
|
||||||
ut_ad(trx->rsegs.m_redo.rseg != 0
|
trx_assign_rseg_low(trx);
|
||||||
|| srv_read_only_mode
|
}
|
||||||
|| srv_force_recovery >= SRV_FORCE_NO_TRX_UNDO);
|
|
||||||
|
|
||||||
trx_sys.register_rw(trx);
|
|
||||||
} else {
|
} else {
|
||||||
if (!trx->is_autocommit_non_locking()) {
|
if (!trx->is_autocommit_non_locking()) {
|
||||||
|
|
||||||
@ -1055,25 +1044,21 @@ trx_write_serialisation_history(
|
|||||||
|
|
||||||
trx_undo_t*& undo = trx->rsegs.m_redo.undo;
|
trx_undo_t*& undo = trx->rsegs.m_redo.undo;
|
||||||
|
|
||||||
if (!undo) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ut_ad(!trx->read_only);
|
ut_ad(!trx->read_only);
|
||||||
ut_ad(!undo || undo->rseg == rseg);
|
|
||||||
rseg->latch.wr_lock(SRW_LOCK_CALL);
|
|
||||||
|
|
||||||
/* Assign the transaction serialisation number and add any
|
/* Assign the transaction serialisation number and add any
|
||||||
undo log to the purge queue. */
|
undo log to the purge queue. */
|
||||||
trx_serialise(trx);
|
|
||||||
if (undo) {
|
if (undo) {
|
||||||
|
rseg->latch.wr_lock(SRW_LOCK_CALL);
|
||||||
|
ut_ad(undo->rseg == rseg);
|
||||||
|
trx_serialise(trx);
|
||||||
UT_LIST_REMOVE(rseg->undo_list, undo);
|
UT_LIST_REMOVE(rseg->undo_list, undo);
|
||||||
trx_purge_add_undo_to_history(trx, undo, mtr);
|
trx_purge_add_undo_to_history(trx, undo, mtr);
|
||||||
|
MONITOR_INC(MONITOR_TRX_COMMIT_UNDO);
|
||||||
|
rseg->latch.wr_unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
rseg->latch.wr_unlock();
|
rseg->release();
|
||||||
|
|
||||||
MONITOR_INC(MONITOR_TRX_COMMIT_UNDO);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/********************************************************************
|
/********************************************************************
|
||||||
@ -1309,10 +1294,6 @@ TRANSACTIONAL_INLINE inline void trx_t::commit_in_memory(const mtr_t *mtr)
|
|||||||
release_locks();
|
release_locks();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (trx_rseg_t *rseg= rsegs.m_redo.rseg)
|
|
||||||
/* This is safe due to us having detached the persistent undo log. */
|
|
||||||
rseg->release();
|
|
||||||
|
|
||||||
if (mtr)
|
if (mtr)
|
||||||
{
|
{
|
||||||
if (trx_undo_t *&undo= rsegs.m_noredo.undo)
|
if (trx_undo_t *&undo= rsegs.m_noredo.undo)
|
||||||
@ -1450,6 +1431,13 @@ TRANSACTIONAL_TARGET void trx_t::commit_low(mtr_t *mtr)
|
|||||||
|
|
||||||
mtr->commit();
|
mtr->commit();
|
||||||
}
|
}
|
||||||
|
else if (trx_rseg_t *rseg= rsegs.m_redo.rseg)
|
||||||
|
{
|
||||||
|
ut_ad(id);
|
||||||
|
ut_ad(!rsegs.m_redo.undo);
|
||||||
|
rseg->release();
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef ENABLED_DEBUG_SYNC
|
#ifdef ENABLED_DEBUG_SYNC
|
||||||
if (debug_sync)
|
if (debug_sync)
|
||||||
DEBUG_SYNC_C("before_trx_state_committed_in_memory");
|
DEBUG_SYNC_C("before_trx_state_committed_in_memory");
|
||||||
@ -2166,11 +2154,7 @@ trx_set_rw_mode(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
trx->rsegs.m_redo.rseg = trx_assign_rseg_low();
|
trx_assign_rseg_low(trx);
|
||||||
ut_ad(trx->rsegs.m_redo.rseg != 0);
|
|
||||||
|
|
||||||
trx_sys.register_rw(trx);
|
|
||||||
ut_ad(trx->id);
|
|
||||||
|
|
||||||
/* So that we can see our own changes. */
|
/* So that we can see our own changes. */
|
||||||
if (trx->read_view.is_open()) {
|
if (trx->read_view.is_open()) {
|
||||||
|
@ -1011,12 +1011,10 @@ static void trx_undo_seg_free(const trx_undo_t *undo)
|
|||||||
@param[in,out] rseg rollback segment
|
@param[in,out] rseg rollback segment
|
||||||
@param[in] id rollback segment slot
|
@param[in] id rollback segment slot
|
||||||
@param[in] page_no undo log segment page number
|
@param[in] page_no undo log segment page number
|
||||||
@param[in,out] max_trx_id the largest observed transaction ID
|
|
||||||
@return the undo log
|
@return the undo log
|
||||||
@retval nullptr on error */
|
@retval nullptr on error */
|
||||||
trx_undo_t *
|
trx_undo_t *
|
||||||
trx_undo_mem_create_at_db_start(trx_rseg_t *rseg, ulint id, uint32_t page_no,
|
trx_undo_mem_create_at_db_start(trx_rseg_t *rseg, ulint id, uint32_t page_no)
|
||||||
trx_id_t &max_trx_id)
|
|
||||||
{
|
{
|
||||||
mtr_t mtr;
|
mtr_t mtr;
|
||||||
XID xid;
|
XID xid;
|
||||||
@ -1054,10 +1052,21 @@ corrupted_type:
|
|||||||
const trx_ulogf_t* const undo_header = block->page.frame + offset;
|
const trx_ulogf_t* const undo_header = block->page.frame + offset;
|
||||||
uint16_t state = mach_read_from_2(TRX_UNDO_SEG_HDR + TRX_UNDO_STATE
|
uint16_t state = mach_read_from_2(TRX_UNDO_SEG_HDR + TRX_UNDO_STATE
|
||||||
+ block->page.frame);
|
+ block->page.frame);
|
||||||
|
|
||||||
|
const trx_id_t trx_id= mach_read_from_8(undo_header + TRX_UNDO_TRX_ID);
|
||||||
|
if (trx_id >> 48) {
|
||||||
|
sql_print_error("InnoDB: corrupted TRX_ID %llx", trx_id);
|
||||||
|
goto corrupted;
|
||||||
|
}
|
||||||
|
/* We will increment rseg->needs_purge, like trx_undo_reuse_cached()
|
||||||
|
would do it, to avoid trouble on rollback or XA COMMIT. */
|
||||||
|
trx_id_t trx_no = trx_id + 1;
|
||||||
|
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case TRX_UNDO_ACTIVE:
|
case TRX_UNDO_ACTIVE:
|
||||||
case TRX_UNDO_PREPARED:
|
case TRX_UNDO_PREPARED:
|
||||||
if (UNIV_LIKELY(type != 1)) {
|
if (UNIV_LIKELY(type != 1)) {
|
||||||
|
trx_no = trx_id + 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
sql_print_error("InnoDB: upgrade from older version than"
|
sql_print_error("InnoDB: upgrade from older version than"
|
||||||
@ -1080,13 +1089,14 @@ corrupted_type:
|
|||||||
goto corrupted_type;
|
goto corrupted_type;
|
||||||
}
|
}
|
||||||
read_trx_no:
|
read_trx_no:
|
||||||
trx_id_t id = mach_read_from_8(TRX_UNDO_TRX_NO + undo_header);
|
trx_no = mach_read_from_8(TRX_UNDO_TRX_NO + undo_header);
|
||||||
if (id >> 48) {
|
if (trx_no >> 48) {
|
||||||
sql_print_error("InnoDB: corrupted TRX_NO %llx", id);
|
sql_print_error("InnoDB: corrupted TRX_NO %llx",
|
||||||
|
trx_no);
|
||||||
goto corrupted;
|
goto corrupted;
|
||||||
}
|
}
|
||||||
if (id > max_trx_id) {
|
if (trx_no < trx_id) {
|
||||||
max_trx_id = id;
|
trx_no = trx_id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1099,13 +1109,8 @@ corrupted_type:
|
|||||||
xid.null();
|
xid.null();
|
||||||
}
|
}
|
||||||
|
|
||||||
trx_id_t trx_id = mach_read_from_8(undo_header + TRX_UNDO_TRX_ID);
|
if (trx_no > rseg->needs_purge) {
|
||||||
if (trx_id >> 48) {
|
rseg->needs_purge = trx_no;
|
||||||
sql_print_error("InnoDB: corrupted TRX_ID %llx", trx_id);
|
|
||||||
goto corrupted;
|
|
||||||
}
|
|
||||||
if (trx_id > max_trx_id) {
|
|
||||||
max_trx_id = trx_id;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
trx_undo_t* undo = trx_undo_mem_create(
|
trx_undo_t* undo = trx_undo_mem_create(
|
||||||
@ -1296,6 +1301,22 @@ buf_block_t*
|
|||||||
trx_undo_reuse_cached(trx_t* trx, trx_rseg_t* rseg, trx_undo_t** pundo,
|
trx_undo_reuse_cached(trx_t* trx, trx_rseg_t* rseg, trx_undo_t** pundo,
|
||||||
mtr_t* mtr)
|
mtr_t* mtr)
|
||||||
{
|
{
|
||||||
|
if (rseg->is_persistent()) {
|
||||||
|
ut_ad(rseg->is_referenced());
|
||||||
|
if (rseg->needs_purge <= trx->id) {
|
||||||
|
/* trx_purge_truncate_history() compares
|
||||||
|
rseg->needs_purge <= head.trx_no
|
||||||
|
so we need to compensate for that.
|
||||||
|
The rseg->needs_purge after crash
|
||||||
|
recovery would be at least trx->id + 1,
|
||||||
|
because that is the minimum possible value
|
||||||
|
assigned by trx_serialise() on commit. */
|
||||||
|
rseg->needs_purge = trx->id + 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ut_ad(!rseg->is_referenced());
|
||||||
|
}
|
||||||
|
|
||||||
trx_undo_t* undo = UT_LIST_GET_FIRST(rseg->undo_cached);
|
trx_undo_t* undo = UT_LIST_GET_FIRST(rseg->undo_cached);
|
||||||
if (!undo) {
|
if (!undo) {
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -1396,8 +1417,7 @@ trx_undo_assign_low(trx_t* trx, trx_rseg_t* rseg, trx_undo_t** undo,
|
|||||||
dberr_t* err, mtr_t* mtr)
|
dberr_t* err, mtr_t* mtr)
|
||||||
{
|
{
|
||||||
ut_d(const bool is_temp = rseg == trx->rsegs.m_noredo.rseg);
|
ut_d(const bool is_temp = rseg == trx->rsegs.m_noredo.rseg);
|
||||||
ut_ad(rseg == trx->rsegs.m_redo.rseg
|
ut_ad(is_temp || rseg == trx->rsegs.m_redo.rseg);
|
||||||
|| rseg == trx->rsegs.m_noredo.rseg);
|
|
||||||
ut_ad(undo == (is_temp
|
ut_ad(undo == (is_temp
|
||||||
? &trx->rsegs.m_noredo.undo
|
? &trx->rsegs.m_noredo.undo
|
||||||
: &trx->rsegs.m_redo.undo));
|
: &trx->rsegs.m_redo.undo));
|
||||||
@ -1417,7 +1437,6 @@ trx_undo_assign_low(trx_t* trx, trx_rseg_t* rseg, trx_undo_t** undo,
|
|||||||
);
|
);
|
||||||
|
|
||||||
rseg->latch.wr_lock(SRW_LOCK_CALL);
|
rseg->latch.wr_lock(SRW_LOCK_CALL);
|
||||||
|
|
||||||
buf_block_t* block = trx_undo_reuse_cached(trx, rseg, undo, mtr);
|
buf_block_t* block = trx_undo_reuse_cached(trx, rseg, undo, mtr);
|
||||||
|
|
||||||
if (!block) {
|
if (!block) {
|
||||||
|
@ -4595,7 +4595,7 @@ static MY_UNICASE_CHARACTER u520p104[]={
|
|||||||
|
|
||||||
MY_UNICASE_CHARACTER *my_unicase_pages_unicode520[4352]=
|
MY_UNICASE_CHARACTER *my_unicase_pages_unicode520[4352]=
|
||||||
{
|
{
|
||||||
u520p00, u520p01, u520p02, u520p03, u520p04, u520p05, plane06, plane06,
|
u520p00, u520p01, u520p02, u520p03, u520p04, u520p05, plane06, plane07,
|
||||||
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
|
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
|
||||||
u520p10, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
|
u520p10, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
|
||||||
NULL, NULL, NULL, NULL, NULL, u520p1D, u520p1E, u520p1F,
|
NULL, NULL, NULL, NULL, NULL, u520p1D, u520p1E, u520p1F,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user