mirror of
https://github.com/MariaDB/server.git
synced 2025-08-09 22:24:09 +03:00
Merge 10.10 into 10.11
This commit is contained in:
@@ -155,6 +155,7 @@ SET(ignored
|
|||||||
"%ignore ${CMAKE_INSTALL_PREFIX}/share/doc"
|
"%ignore ${CMAKE_INSTALL_PREFIX}/share/doc"
|
||||||
"%ignore ${CMAKE_INSTALL_PREFIX}/share/man"
|
"%ignore ${CMAKE_INSTALL_PREFIX}/share/man"
|
||||||
"%ignore ${CMAKE_INSTALL_PREFIX}/share/man/man1"
|
"%ignore ${CMAKE_INSTALL_PREFIX}/share/man/man1"
|
||||||
|
"%ignore ${CMAKE_INSTALL_PREFIX}/share/man/man3"
|
||||||
"%ignore ${CMAKE_INSTALL_PREFIX}/share/man/man8"
|
"%ignore ${CMAKE_INSTALL_PREFIX}/share/man/man8"
|
||||||
"%ignore ${CMAKE_INSTALL_PREFIX}/share/pkgconfig"
|
"%ignore ${CMAKE_INSTALL_PREFIX}/share/pkgconfig"
|
||||||
)
|
)
|
||||||
|
@@ -69,6 +69,9 @@ extern struct wsrep_service_st {
|
|||||||
void (*wsrep_thd_self_abort_func)(MYSQL_THD thd);
|
void (*wsrep_thd_self_abort_func)(MYSQL_THD thd);
|
||||||
int (*wsrep_thd_append_key_func)(MYSQL_THD thd, const struct wsrep_key* key,
|
int (*wsrep_thd_append_key_func)(MYSQL_THD thd, const struct wsrep_key* key,
|
||||||
int n_keys, enum Wsrep_service_key_type);
|
int n_keys, enum Wsrep_service_key_type);
|
||||||
|
int (*wsrep_thd_append_table_key_func)(MYSQL_THD thd, const char* db,
|
||||||
|
const char* table, enum Wsrep_service_key_type);
|
||||||
|
my_bool (*wsrep_thd_is_local_transaction)(const MYSQL_THD thd);
|
||||||
const char* (*wsrep_thd_client_state_str_func)(const MYSQL_THD thd);
|
const char* (*wsrep_thd_client_state_str_func)(const MYSQL_THD thd);
|
||||||
const char* (*wsrep_thd_client_mode_str_func)(const MYSQL_THD thd);
|
const char* (*wsrep_thd_client_mode_str_func)(const MYSQL_THD thd);
|
||||||
const char* (*wsrep_thd_transaction_state_str_func)(const MYSQL_THD thd);
|
const char* (*wsrep_thd_transaction_state_str_func)(const MYSQL_THD thd);
|
||||||
@@ -121,6 +124,8 @@ extern struct wsrep_service_st {
|
|||||||
#define wsrep_thd_is_local(T) wsrep_service->wsrep_thd_is_local_func(T)
|
#define wsrep_thd_is_local(T) wsrep_service->wsrep_thd_is_local_func(T)
|
||||||
#define wsrep_thd_self_abort(T) wsrep_service->wsrep_thd_self_abort_func(T)
|
#define wsrep_thd_self_abort(T) wsrep_service->wsrep_thd_self_abort_func(T)
|
||||||
#define wsrep_thd_append_key(T,W,N,K) wsrep_service->wsrep_thd_append_key_func(T,W,N,K)
|
#define wsrep_thd_append_key(T,W,N,K) wsrep_service->wsrep_thd_append_key_func(T,W,N,K)
|
||||||
|
#define wsrep_thd_append_table_key(T,D,B,K) wsrep_service->wsrep_thd_append_table_key_func(T,D,B,K)
|
||||||
|
#define wsrep_thd_is_local_transaction(T) wsrep_service->wsrep_thd_is_local_transaction_func(T)
|
||||||
#define wsrep_thd_client_state_str(T) wsrep_service->wsrep_thd_client_state_str_func(T)
|
#define wsrep_thd_client_state_str(T) wsrep_service->wsrep_thd_client_state_str_func(T)
|
||||||
#define wsrep_thd_client_mode_str(T) wsrep_service->wsrep_thd_client_mode_str_func(T)
|
#define wsrep_thd_client_mode_str(T) wsrep_service->wsrep_thd_client_mode_str_func(T)
|
||||||
#define wsrep_thd_transaction_state_str(T) wsrep_service->wsrep_thd_transaction_state_str_func(T)
|
#define wsrep_thd_transaction_state_str(T) wsrep_service->wsrep_thd_transaction_state_str_func(T)
|
||||||
@@ -226,6 +231,13 @@ extern "C" int wsrep_thd_append_key(MYSQL_THD thd,
|
|||||||
int n_keys,
|
int n_keys,
|
||||||
enum Wsrep_service_key_type);
|
enum Wsrep_service_key_type);
|
||||||
|
|
||||||
|
extern "C" int wsrep_thd_append_table_key(MYSQL_THD thd,
|
||||||
|
const char* db,
|
||||||
|
const char* table,
|
||||||
|
enum Wsrep_service_key_type);
|
||||||
|
|
||||||
|
extern "C" my_bool wsrep_thd_is_local_transaction(const MYSQL_THD thd);
|
||||||
|
|
||||||
extern const char* wsrep_sr_table_name_full;
|
extern const char* wsrep_sr_table_name_full;
|
||||||
|
|
||||||
extern "C" const char* wsrep_get_sr_table_name();
|
extern "C" const char* wsrep_get_sr_table_name();
|
||||||
|
@@ -11,7 +11,6 @@
|
|||||||
##############################################################################
|
##############################################################################
|
||||||
|
|
||||||
galera_as_slave_ctas : MDEV-28378 timeout
|
galera_as_slave_ctas : MDEV-28378 timeout
|
||||||
galera_bf_abort_at_after_statement : Timeout in wait_condition.inc for SELECT COUNT(*) = 1 FROM t1 where id = 1 and val = 3
|
|
||||||
galera_pc_recovery : MDEV-25199 cluster fails to start up
|
galera_pc_recovery : MDEV-25199 cluster fails to start up
|
||||||
galera_sst_encrypted : MDEV-29876 Galera test failure on galera_sst_encrypted
|
galera_sst_encrypted : MDEV-29876 Galera test failure on galera_sst_encrypted
|
||||||
MW-284 : MDEV-29861 Galera test case hangs
|
MW-284 : MDEV-29861 Galera test case hangs
|
||||||
|
30
mysql-test/suite/galera/r/galera_insert_bulk.result
Normal file
30
mysql-test/suite/galera/r/galera_insert_bulk.result
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
connection node_2;
|
||||||
|
connection node_1;
|
||||||
|
connection node_1;
|
||||||
|
CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
|
||||||
|
SET foreign_key_checks = 0;
|
||||||
|
SET unique_checks = 0;
|
||||||
|
START TRANSACTION;
|
||||||
|
connection node_2;
|
||||||
|
SET foreign_key_checks = 1;
|
||||||
|
SET unique_checks = 1;
|
||||||
|
INSERT INTO t1 VALUES (1001);
|
||||||
|
connection node_1;
|
||||||
|
COMMIT;
|
||||||
|
ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
|
||||||
|
DROP TABLE t1;
|
||||||
|
connection node_1;
|
||||||
|
CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
|
||||||
|
START TRANSACTION;
|
||||||
|
connection node_2;
|
||||||
|
SET foreign_key_checks = 1;
|
||||||
|
SET unique_checks = 1;
|
||||||
|
START TRANSACTION;
|
||||||
|
INSERT INTO t1 VALUES (1001);
|
||||||
|
connection node_1;
|
||||||
|
COMMIT;
|
||||||
|
2
|
||||||
|
connection node_2;
|
||||||
|
COMMIT;
|
||||||
|
ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
|
||||||
|
DROP TABLE t1;
|
88
mysql-test/suite/galera/t/galera_insert_bulk.test
Normal file
88
mysql-test/suite/galera/t/galera_insert_bulk.test
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
#
|
||||||
|
# Test that bulk insert replicates as table-level exclusive key and
|
||||||
|
# rolls back properly if needed.
|
||||||
|
#
|
||||||
|
|
||||||
|
--source include/galera_cluster.inc
|
||||||
|
--source include/have_innodb.inc
|
||||||
|
|
||||||
|
#
|
||||||
|
# Make bulk insert BF-abort, but regular insert succeed.
|
||||||
|
#
|
||||||
|
|
||||||
|
--connection node_1
|
||||||
|
CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
|
||||||
|
|
||||||
|
# Disable foreign and unique key checks to allow bulk insert.
|
||||||
|
SET foreign_key_checks = 0;
|
||||||
|
SET unique_checks = 0;
|
||||||
|
|
||||||
|
START TRANSACTION;
|
||||||
|
|
||||||
|
--let $count=0
|
||||||
|
--disable_query_log
|
||||||
|
while ($count < 1000)
|
||||||
|
{
|
||||||
|
--eval INSERT INTO t1 VALUES ($count)
|
||||||
|
--inc $count
|
||||||
|
}
|
||||||
|
--enable_query_log
|
||||||
|
|
||||||
|
--connection node_2
|
||||||
|
|
||||||
|
# Disable bulk insert.
|
||||||
|
SET foreign_key_checks = 1;
|
||||||
|
SET unique_checks = 1;
|
||||||
|
|
||||||
|
# Insert a value out of the bulk insert range.
|
||||||
|
INSERT INTO t1 VALUES (1001);
|
||||||
|
|
||||||
|
--connection node_1
|
||||||
|
--error ER_LOCK_DEADLOCK
|
||||||
|
COMMIT;
|
||||||
|
|
||||||
|
DROP TABLE t1;
|
||||||
|
|
||||||
|
#
|
||||||
|
# Make bulk insert succeed, but regular insert BF-abort.
|
||||||
|
#
|
||||||
|
|
||||||
|
--connection node_1
|
||||||
|
CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
|
||||||
|
|
||||||
|
--let $before_bulk_keys = `SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_repl_keys'`
|
||||||
|
|
||||||
|
START TRANSACTION;
|
||||||
|
|
||||||
|
--let $count=0
|
||||||
|
--disable_query_log
|
||||||
|
while ($count < 1000)
|
||||||
|
{
|
||||||
|
--eval INSERT INTO t1 VALUES ($count)
|
||||||
|
--inc $count
|
||||||
|
}
|
||||||
|
--enable_query_log
|
||||||
|
|
||||||
|
--connection node_2
|
||||||
|
|
||||||
|
# Disable bulk insert.
|
||||||
|
SET foreign_key_checks = 1;
|
||||||
|
SET unique_checks = 1;
|
||||||
|
|
||||||
|
START TRANSACTION;
|
||||||
|
|
||||||
|
# Insert a value out of the bulk insert range.
|
||||||
|
INSERT INTO t1 VALUES (1001);
|
||||||
|
|
||||||
|
--connection node_1
|
||||||
|
COMMIT;
|
||||||
|
|
||||||
|
# Expect two keys to be added for bulk insert: DB-level shared key and table-level exclusive key.
|
||||||
|
--let $bulk_keys_count = `SELECT VARIABLE_VALUE - $before_bulk_keys FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_repl_keys'`
|
||||||
|
--echo $bulk_keys_count
|
||||||
|
|
||||||
|
--connection node_2
|
||||||
|
--error ER_LOCK_DEADLOCK
|
||||||
|
COMMIT;
|
||||||
|
|
||||||
|
DROP TABLE t1;
|
@@ -12,10 +12,8 @@
|
|||||||
|
|
||||||
galera_2_cluster : MDEV-29877 Galera test failure on galera_2_cluster
|
galera_2_cluster : MDEV-29877 Galera test failure on galera_2_cluster
|
||||||
galera_gtid_2_cluster : MDEV-29877 Galera test failure on galera_2_cluster
|
galera_gtid_2_cluster : MDEV-29877 Galera test failure on galera_2_cluster
|
||||||
galera_parallel_apply_3nodes : MDEV-29368 DEBUG_SYNC timeout
|
|
||||||
galera_ipv6_mariabackup : MDEV-24097
|
galera_ipv6_mariabackup : MDEV-24097
|
||||||
galera_ipv6_mariabackup_section : MDEV-24097, MDEV-22195
|
galera_ipv6_mariabackup_section : MDEV-24097, MDEV-22195
|
||||||
galera_parallel_apply_3nodes : MDEV-29774 Galera test galera_parallel_apply_3nodes is unstable
|
|
||||||
galera_vote_rejoin_mysqldump : MDEV-24481: galera_3nodes.galera_vote_rejoin_mysqldump MTR failed: mysql_shutdown failed
|
galera_vote_rejoin_mysqldump : MDEV-24481: galera_3nodes.galera_vote_rejoin_mysqldump MTR failed: mysql_shutdown failed
|
||||||
galera_ssl_reload : MDEV-30172 At line 50: mysql_shutdown failed
|
galera_ssl_reload : MDEV-30172 At line 50: mysql_shutdown failed
|
||||||
GCF-354 : mysqltest: At line 39: query 'DROP TABLE test.t1' failed: 1047: WSREP has not yet prepared node for application use
|
GCF-354 : mysqltest: At line 39: query 'DROP TABLE test.t1' failed: 1047: WSREP has not yet prepared node for application use
|
||||||
|
@@ -1,51 +0,0 @@
|
|||||||
#
|
|
||||||
# Bug#69122 - INNODB DOESN'T REDO-LOG INSERT BUFFER MERGE
|
|
||||||
# OPERATION IF IT IS DONE IN-PLACE
|
|
||||||
#
|
|
||||||
call mtr.add_suppression("InnoDB: innodb_read_only prevents crash recovery");
|
|
||||||
call mtr.add_suppression("Plugin initialization aborted at srv0start\\.cc");
|
|
||||||
call mtr.add_suppression("Plugin 'InnoDB'");
|
|
||||||
FLUSH TABLES;
|
|
||||||
CREATE TABLE t1(
|
|
||||||
a INT AUTO_INCREMENT PRIMARY KEY,
|
|
||||||
b CHAR(1),
|
|
||||||
c INT,
|
|
||||||
INDEX(b))
|
|
||||||
ENGINE=InnoDB STATS_PERSISTENT=0;
|
|
||||||
SET GLOBAL innodb_change_buffering_debug = 1;
|
|
||||||
SET GLOBAL innodb_change_buffering = all;
|
|
||||||
Warnings:
|
|
||||||
Warning 1287 '@@innodb_change_buffering' is deprecated and will be removed in a future release
|
|
||||||
INSERT INTO t1 SELECT 0,'x',1 FROM seq_1_to_8192;
|
|
||||||
BEGIN;
|
|
||||||
SELECT b FROM t1 LIMIT 3;
|
|
||||||
b
|
|
||||||
x
|
|
||||||
x
|
|
||||||
x
|
|
||||||
connect con1,localhost,root,,;
|
|
||||||
BEGIN;
|
|
||||||
DELETE FROM t1 WHERE a=1;
|
|
||||||
INSERT INTO t1 VALUES(1,'X',1);
|
|
||||||
SET DEBUG_DBUG='+d,crash_after_log_ibuf_upd_inplace';
|
|
||||||
SELECT b FROM t1 LIMIT 3;
|
|
||||||
ERROR HY000: Lost connection to server during query
|
|
||||||
disconnect con1;
|
|
||||||
connection default;
|
|
||||||
FOUND 1 /Wrote log record for ibuf update in place operation/ in mysqld.1.err
|
|
||||||
# restart: --innodb-read-only
|
|
||||||
CHECK TABLE t1;
|
|
||||||
Table Op Msg_type Msg_text
|
|
||||||
test.t1 check Error Unknown storage engine 'InnoDB'
|
|
||||||
test.t1 check error Corrupt
|
|
||||||
FOUND 1 /innodb_read_only prevents crash recovery/ in mysqld.1.err
|
|
||||||
# restart: --innodb-force-recovery=5 --debug-dbug=d,crash_after_log_ibuf_upd_inplace
|
|
||||||
SELECT * FROM t1 LIMIT 1;
|
|
||||||
a b c
|
|
||||||
1 X 1
|
|
||||||
SET GLOBAL innodb_fast_shutdown=0;
|
|
||||||
# restart
|
|
||||||
CHECK TABLE t1;
|
|
||||||
Table Op Msg_type Msg_text
|
|
||||||
test.t1 check status OK
|
|
||||||
DROP TABLE t1;
|
|
@@ -1,405 +0,0 @@
|
|||||||
SET GLOBAL innodb_adaptive_hash_index = false;
|
|
||||||
SET GLOBAL innodb_stats_persistent = false;
|
|
||||||
connect con1,localhost,root,,;
|
|
||||||
connect con2,localhost,root,,;
|
|
||||||
connect con3,localhost,root,,;
|
|
||||||
CREATE TABLE t1 (
|
|
||||||
a00 CHAR(255) NOT NULL DEFAULT 'a',
|
|
||||||
a01 CHAR(255) NOT NULL DEFAULT 'a',
|
|
||||||
a02 CHAR(255) NOT NULL DEFAULT 'a',
|
|
||||||
a03 CHAR(255) NOT NULL DEFAULT 'a',
|
|
||||||
a04 CHAR(255) NOT NULL DEFAULT 'a',
|
|
||||||
a05 CHAR(255) NOT NULL DEFAULT 'a',
|
|
||||||
a06 CHAR(255) NOT NULL DEFAULT 'a',
|
|
||||||
b INT NOT NULL DEFAULT 0
|
|
||||||
) ENGINE = InnoDB;
|
|
||||||
ALTER TABLE t1 ADD PRIMARY KEY(
|
|
||||||
a00,
|
|
||||||
a01,
|
|
||||||
a02,
|
|
||||||
a03,
|
|
||||||
a04,
|
|
||||||
a05,
|
|
||||||
a06
|
|
||||||
);
|
|
||||||
ANALYZE TABLE t1;
|
|
||||||
Table Op Msg_type Msg_text
|
|
||||||
test.t1 analyze status Engine-independent statistics collected
|
|
||||||
test.t1 analyze status OK
|
|
||||||
SELECT CLUST_INDEX_SIZE FROM information_schema.INNODB_SYS_TABLESTATS WHERE NAME = 'test/t1';
|
|
||||||
CLUST_INDEX_SIZE
|
|
||||||
1
|
|
||||||
SET GLOBAL innodb_limit_optimistic_insert_debug = 7;
|
|
||||||
BEGIN;
|
|
||||||
INSERT INTO t1 (a00) VALUES ('aa');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('ab');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('ac');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('ad');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('ae');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('af');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('ag');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('ah');
|
|
||||||
COMMIT;
|
|
||||||
ANALYZE TABLE t1;
|
|
||||||
Table Op Msg_type Msg_text
|
|
||||||
test.t1 analyze status Engine-independent statistics collected
|
|
||||||
test.t1 analyze status OK
|
|
||||||
SELECT CLUST_INDEX_SIZE FROM information_schema.INNODB_SYS_TABLESTATS WHERE NAME = 'test/t1';
|
|
||||||
CLUST_INDEX_SIZE
|
|
||||||
3
|
|
||||||
BEGIN;
|
|
||||||
INSERT INTO t1 (a00) VALUES ('ai');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('aj');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('ak');
|
|
||||||
COMMIT;
|
|
||||||
ANALYZE TABLE t1;
|
|
||||||
Table Op Msg_type Msg_text
|
|
||||||
test.t1 analyze status Engine-independent statistics collected
|
|
||||||
test.t1 analyze status OK
|
|
||||||
SELECT CLUST_INDEX_SIZE FROM information_schema.INNODB_SYS_TABLESTATS WHERE NAME = 'test/t1';
|
|
||||||
CLUST_INDEX_SIZE
|
|
||||||
4
|
|
||||||
BEGIN;
|
|
||||||
INSERT INTO t1 (a00) VALUES ('al');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('am');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('an');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('ao');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('ap');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('aq');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('ar');
|
|
||||||
COMMIT;
|
|
||||||
ANALYZE TABLE t1;
|
|
||||||
Table Op Msg_type Msg_text
|
|
||||||
test.t1 analyze status Engine-independent statistics collected
|
|
||||||
test.t1 analyze status OK
|
|
||||||
SELECT CLUST_INDEX_SIZE FROM information_schema.INNODB_SYS_TABLESTATS WHERE NAME = 'test/t1';
|
|
||||||
CLUST_INDEX_SIZE
|
|
||||||
5
|
|
||||||
BEGIN;
|
|
||||||
INSERT INTO t1 (a00) VALUES ('as');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('at');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('au');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('av');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('aw');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('ax');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('ay');
|
|
||||||
COMMIT;
|
|
||||||
ANALYZE TABLE t1;
|
|
||||||
Table Op Msg_type Msg_text
|
|
||||||
test.t1 analyze status Engine-independent statistics collected
|
|
||||||
test.t1 analyze status OK
|
|
||||||
SELECT CLUST_INDEX_SIZE FROM information_schema.INNODB_SYS_TABLESTATS WHERE NAME = 'test/t1';
|
|
||||||
CLUST_INDEX_SIZE
|
|
||||||
6
|
|
||||||
BEGIN;
|
|
||||||
INSERT INTO t1 (a00) VALUES ('az');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('ba');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('bb');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('bc');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('bd');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('be');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('bf');
|
|
||||||
COMMIT;
|
|
||||||
ANALYZE TABLE t1;
|
|
||||||
Table Op Msg_type Msg_text
|
|
||||||
test.t1 analyze status Engine-independent statistics collected
|
|
||||||
test.t1 analyze status OK
|
|
||||||
SELECT CLUST_INDEX_SIZE FROM information_schema.INNODB_SYS_TABLESTATS WHERE NAME = 'test/t1';
|
|
||||||
CLUST_INDEX_SIZE
|
|
||||||
7
|
|
||||||
BEGIN;
|
|
||||||
INSERT INTO t1 (a00) VALUES ('bg');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('bh');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('bi');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('bj');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('bk');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('bl');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('bm');
|
|
||||||
COMMIT;
|
|
||||||
ANALYZE TABLE t1;
|
|
||||||
Table Op Msg_type Msg_text
|
|
||||||
test.t1 analyze status Engine-independent statistics collected
|
|
||||||
test.t1 analyze status OK
|
|
||||||
SELECT CLUST_INDEX_SIZE FROM information_schema.INNODB_SYS_TABLESTATS WHERE NAME = 'test/t1';
|
|
||||||
CLUST_INDEX_SIZE
|
|
||||||
8
|
|
||||||
BEGIN;
|
|
||||||
INSERT INTO t1 (a00) VALUES ('bn');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('bo');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('bp');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('bq');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('br');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('bs');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('bt');
|
|
||||||
COMMIT;
|
|
||||||
ANALYZE TABLE t1;
|
|
||||||
Table Op Msg_type Msg_text
|
|
||||||
test.t1 analyze status Engine-independent statistics collected
|
|
||||||
test.t1 analyze status OK
|
|
||||||
SELECT CLUST_INDEX_SIZE FROM information_schema.INNODB_SYS_TABLESTATS WHERE NAME = 'test/t1';
|
|
||||||
CLUST_INDEX_SIZE
|
|
||||||
11
|
|
||||||
BEGIN;
|
|
||||||
INSERT INTO t1 (a00) VALUES ('bu');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('bv');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('bw');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('bx');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('by');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('bz');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('ca');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('cb');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('cc');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('cd');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('ce');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('cf');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('cg');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('ch');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('ci');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('cj');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('ck');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('cl');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('cm');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('cn');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('co');
|
|
||||||
COMMIT;
|
|
||||||
ANALYZE TABLE t1;
|
|
||||||
Table Op Msg_type Msg_text
|
|
||||||
test.t1 analyze status Engine-independent statistics collected
|
|
||||||
test.t1 analyze status OK
|
|
||||||
SELECT CLUST_INDEX_SIZE FROM information_schema.INNODB_SYS_TABLESTATS WHERE NAME = 'test/t1';
|
|
||||||
CLUST_INDEX_SIZE
|
|
||||||
15
|
|
||||||
BEGIN;
|
|
||||||
INSERT INTO t1 (a00) VALUES ('cp');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('cq');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('cr');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('cs');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('ct');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('cu');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('cv');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('cw');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('cx');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('cy');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('cz');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('da');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('db');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('dc');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('dd');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('de');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('df');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('dg');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('dh');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('di');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('dj');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('dk');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('dl');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('dm');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('dn');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('do');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('dp');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('dq');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('dr');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('ds');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('dt');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('du');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('dv');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('dw');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('dx');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('dy');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('dz');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('ea');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('eb');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('ec');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('ed');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('ee');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('ef');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('eg');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('eh');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('ei');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('ej');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('ek');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('el');
|
|
||||||
COMMIT;
|
|
||||||
ANALYZE TABLE t1;
|
|
||||||
Table Op Msg_type Msg_text
|
|
||||||
test.t1 analyze status Engine-independent statistics collected
|
|
||||||
test.t1 analyze status OK
|
|
||||||
SELECT CLUST_INDEX_SIZE FROM information_schema.INNODB_SYS_TABLESTATS WHERE NAME = 'test/t1';
|
|
||||||
CLUST_INDEX_SIZE
|
|
||||||
23
|
|
||||||
BEGIN;
|
|
||||||
INSERT INTO t1 (a00) VALUES ('em');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('en');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('eo');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('ep');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('eq');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('er');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('es');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('et');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('eu');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('ev');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('ew');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('ex');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('ey');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('ez');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('fa');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('fb');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('fc');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('fd');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('fe');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('ff');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('fg');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('fh');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('fi');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('fj');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('fk');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('fl');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('fm');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('fn');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('fo');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('fp');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('fq');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('fr');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('fs');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('ft');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('fu');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('fv');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('fw');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('fx');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('fy');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('fz');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('ga');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('gb');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('gc');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('gd');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('ge');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('gf');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('gg');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('gh');
|
|
||||||
COMMIT;
|
|
||||||
ANALYZE TABLE t1;
|
|
||||||
Table Op Msg_type Msg_text
|
|
||||||
test.t1 analyze status Engine-independent statistics collected
|
|
||||||
test.t1 analyze status OK
|
|
||||||
SELECT CLUST_INDEX_SIZE FROM information_schema.INNODB_SYS_TABLESTATS WHERE NAME = 'test/t1';
|
|
||||||
CLUST_INDEX_SIZE
|
|
||||||
29
|
|
||||||
SET GLOBAL innodb_limit_optimistic_insert_debug = 0;
|
|
||||||
# Test start
|
|
||||||
SET DEBUG_SYNC = 'RESET';
|
|
||||||
INSERT INTO t1 (a00) VALUES ('bfa');
|
|
||||||
connection con1;
|
|
||||||
SET DEBUG_SYNC = 'before_insert_pessimitic_row_ins_clust SIGNAL reached WAIT_FOR continue';
|
|
||||||
INSERT INTO t1 (a00) VALUES ('bfb');
|
|
||||||
connection con2;
|
|
||||||
SET DEBUG_SYNC = 'now WAIT_FOR reached';
|
|
||||||
SELECT a00,a01 FROM t1 WHERE a00 = 'aa';
|
|
||||||
a00 a01
|
|
||||||
aa a
|
|
||||||
SELECT a00,a01 FROM t1 WHERE a00 = 'aq';
|
|
||||||
a00 a01
|
|
||||||
aq a
|
|
||||||
SELECT a00,a01 FROM t1 WHERE a00 = 'cp';
|
|
||||||
a00 a01
|
|
||||||
cp a
|
|
||||||
SELECT a00,a01 FROM t1 WHERE a00 = 'el';
|
|
||||||
a00 a01
|
|
||||||
el a
|
|
||||||
SET DEBUG_SYNC = 'rw_s_lock_waiting SIGNAL lockwait1';
|
|
||||||
SELECT a00,a01 FROM t1 WHERE a00 = 'ar';
|
|
||||||
connection con3;
|
|
||||||
SET DEBUG_SYNC = 'rw_s_lock_waiting SIGNAL lockwait2';
|
|
||||||
SELECT a00,a01 FROM t1 WHERE a00 = 'cn';
|
|
||||||
connection default;
|
|
||||||
SET DEBUG_SYNC = 'now WAIT_FOR lockwait1 TIMEOUT 1';
|
|
||||||
SET DEBUG_SYNC = 'now WAIT_FOR lockwait2 TIMEOUT 1';
|
|
||||||
SET DEBUG_SYNC = 'now SIGNAL continue';
|
|
||||||
connection con1;
|
|
||||||
connection con2;
|
|
||||||
a00 a01
|
|
||||||
ar a
|
|
||||||
connection con3;
|
|
||||||
a00 a01
|
|
||||||
cn a
|
|
||||||
connection default;
|
|
||||||
ANALYZE TABLE t1;
|
|
||||||
Table Op Msg_type Msg_text
|
|
||||||
test.t1 analyze status Engine-independent statistics collected
|
|
||||||
test.t1 analyze status OK
|
|
||||||
SELECT CLUST_INDEX_SIZE FROM information_schema.INNODB_SYS_TABLESTATS WHERE NAME = 'test/t1';
|
|
||||||
CLUST_INDEX_SIZE
|
|
||||||
30
|
|
||||||
SET DEBUG_SYNC = 'RESET';
|
|
||||||
INSERT INTO t1 (a00) VALUES ('coa');
|
|
||||||
connection con1;
|
|
||||||
SET DEBUG_SYNC = 'before_insert_pessimitic_row_ins_clust SIGNAL reached WAIT_FOR continue';
|
|
||||||
INSERT INTO t1 (a00) VALUES ('cob');
|
|
||||||
connection con2;
|
|
||||||
SET DEBUG_SYNC = 'now WAIT_FOR reached';
|
|
||||||
SET DEBUG_SYNC = 'rw_s_lock_waiting SIGNAL lockwait1';
|
|
||||||
SELECT a00,a01 FROM t1 WHERE a00 = 'aa';
|
|
||||||
connection con3;
|
|
||||||
SET DEBUG_SYNC = 'rw_s_lock_waiting SIGNAL lockwait2';
|
|
||||||
SELECT a00,a01 FROM t1 WHERE a00 = 'el';
|
|
||||||
connection default;
|
|
||||||
SET DEBUG_SYNC = 'now WAIT_FOR lockwait1 TIMEOUT 1';
|
|
||||||
SET DEBUG_SYNC = 'now WAIT_FOR lockwait2 TIMEOUT 1';
|
|
||||||
SET DEBUG_SYNC = 'now SIGNAL continue';
|
|
||||||
connection con1;
|
|
||||||
connection con2;
|
|
||||||
a00 a01
|
|
||||||
aa a
|
|
||||||
connection con3;
|
|
||||||
a00 a01
|
|
||||||
el a
|
|
||||||
connection default;
|
|
||||||
ANALYZE TABLE t1;
|
|
||||||
Table Op Msg_type Msg_text
|
|
||||||
test.t1 analyze status Engine-independent statistics collected
|
|
||||||
test.t1 analyze status OK
|
|
||||||
SELECT CLUST_INDEX_SIZE FROM information_schema.INNODB_SYS_TABLESTATS WHERE NAME = 'test/t1';
|
|
||||||
CLUST_INDEX_SIZE
|
|
||||||
31
|
|
||||||
SET DEBUG_SYNC = 'RESET';
|
|
||||||
INSERT INTO t1 (a00) VALUES ('gba');
|
|
||||||
connection con1;
|
|
||||||
SET DEBUG_SYNC = 'before_insert_pessimitic_row_ins_clust SIGNAL reached WAIT_FOR continue';
|
|
||||||
INSERT INTO t1 (a00) VALUES ('gbb');
|
|
||||||
connection con2;
|
|
||||||
SET DEBUG_SYNC = 'now WAIT_FOR reached';
|
|
||||||
SELECT a00,a01 FROM t1 WHERE a00 = 'aa';
|
|
||||||
a00 a01
|
|
||||||
aa a
|
|
||||||
SELECT a00,a01 FROM t1 WHERE a00 = 'ek';
|
|
||||||
a00 a01
|
|
||||||
ek a
|
|
||||||
SET DEBUG_SYNC = 'rw_s_lock_waiting SIGNAL lockwait1';
|
|
||||||
SELECT a00,a01 FROM t1 WHERE a00 = 'el';
|
|
||||||
connection con3;
|
|
||||||
SET DEBUG_SYNC = 'rw_s_lock_waiting SIGNAL lockwait2';
|
|
||||||
SELECT a00,a01 FROM t1 WHERE a00 = 'gb';
|
|
||||||
connection default;
|
|
||||||
SET DEBUG_SYNC = 'now WAIT_FOR lockwait1 TIMEOUT 1';
|
|
||||||
SET DEBUG_SYNC = 'now WAIT_FOR lockwait2 TIMEOUT 1';
|
|
||||||
SET DEBUG_SYNC = 'now SIGNAL continue';
|
|
||||||
connection con1;
|
|
||||||
connection con2;
|
|
||||||
a00 a01
|
|
||||||
el a
|
|
||||||
connection con3;
|
|
||||||
a00 a01
|
|
||||||
gb a
|
|
||||||
connection default;
|
|
||||||
ANALYZE TABLE t1;
|
|
||||||
Table Op Msg_type Msg_text
|
|
||||||
test.t1 analyze status Engine-independent statistics collected
|
|
||||||
test.t1 analyze status OK
|
|
||||||
SELECT CLUST_INDEX_SIZE FROM information_schema.INNODB_SYS_TABLESTATS WHERE NAME = 'test/t1';
|
|
||||||
CLUST_INDEX_SIZE
|
|
||||||
32
|
|
||||||
SET DEBUG_SYNC = 'RESET';
|
|
||||||
connection default;
|
|
||||||
disconnect con1;
|
|
||||||
disconnect con2;
|
|
||||||
disconnect con3;
|
|
||||||
DROP TABLE t1;
|
|
@@ -45,6 +45,10 @@ SET tx_read_only=1;
|
|||||||
BEGIN;
|
BEGIN;
|
||||||
INSERT INTO t2 VALUES(0);
|
INSERT INTO t2 VALUES(0);
|
||||||
INSERT INTO t VALUES(0);
|
INSERT INTO t VALUES(0);
|
||||||
|
ROLLBACK;
|
||||||
|
BEGIN;
|
||||||
|
INSERT INTO t2 VALUES(0);
|
||||||
|
INSERT INTO t VALUES(0);
|
||||||
COMMIT;
|
COMMIT;
|
||||||
INSERT INTO t VALUES(0);
|
INSERT INTO t VALUES(0);
|
||||||
DROP TEMPORARY TABLE t,t2;
|
DROP TEMPORARY TABLE t,t2;
|
||||||
|
@@ -1 +0,0 @@
|
|||||||
--innodb_buffer_pool_size=24M
|
|
@@ -1,78 +0,0 @@
|
|||||||
--echo #
|
|
||||||
--echo # Bug#69122 - INNODB DOESN'T REDO-LOG INSERT BUFFER MERGE
|
|
||||||
--echo # OPERATION IF IT IS DONE IN-PLACE
|
|
||||||
--echo #
|
|
||||||
--source include/have_innodb.inc
|
|
||||||
# innodb_change_buffering_debug option is debug only
|
|
||||||
--source include/have_debug.inc
|
|
||||||
# Embedded server does not support crashing
|
|
||||||
--source include/not_embedded.inc
|
|
||||||
# DBUG_SUICIDE() hangs under valgrind
|
|
||||||
--source include/not_valgrind.inc
|
|
||||||
# This test is slow on buildbot.
|
|
||||||
--source include/big_test.inc
|
|
||||||
--source include/have_sequence.inc
|
|
||||||
|
|
||||||
call mtr.add_suppression("InnoDB: innodb_read_only prevents crash recovery");
|
|
||||||
call mtr.add_suppression("Plugin initialization aborted at srv0start\\.cc");
|
|
||||||
call mtr.add_suppression("Plugin 'InnoDB'");
|
|
||||||
FLUSH TABLES;
|
|
||||||
|
|
||||||
CREATE TABLE t1(
|
|
||||||
a INT AUTO_INCREMENT PRIMARY KEY,
|
|
||||||
b CHAR(1),
|
|
||||||
c INT,
|
|
||||||
INDEX(b))
|
|
||||||
ENGINE=InnoDB STATS_PERSISTENT=0;
|
|
||||||
|
|
||||||
--let $_server_id= `SELECT @@server_id`
|
|
||||||
--let $_expect_file_name= $MYSQLTEST_VARDIR/tmp/mysqld.$_server_id.expect
|
|
||||||
|
|
||||||
# The flag innodb_change_buffering_debug is only available in debug builds.
|
|
||||||
# It instructs InnoDB to try to evict pages from the buffer pool when
|
|
||||||
# change buffering is possible, so that the change buffer will be used
|
|
||||||
# whenever possible.
|
|
||||||
SET GLOBAL innodb_change_buffering_debug = 1;
|
|
||||||
SET GLOBAL innodb_change_buffering = all;
|
|
||||||
let SEARCH_FILE = $MYSQLTEST_VARDIR/log/mysqld.1.err;
|
|
||||||
|
|
||||||
# Create enough rows for the table, so that the change buffer will be
|
|
||||||
# used for modifying the secondary index page. There must be multiple
|
|
||||||
# index pages, because changes to the root page are never buffered.
|
|
||||||
INSERT INTO t1 SELECT 0,'x',1 FROM seq_1_to_8192;
|
|
||||||
|
|
||||||
BEGIN;
|
|
||||||
SELECT b FROM t1 LIMIT 3;
|
|
||||||
|
|
||||||
connect (con1,localhost,root,,);
|
|
||||||
BEGIN;
|
|
||||||
DELETE FROM t1 WHERE a=1;
|
|
||||||
# This should be buffered, if innodb_change_buffering_debug = 1 is in effect.
|
|
||||||
INSERT INTO t1 VALUES(1,'X',1);
|
|
||||||
|
|
||||||
SET DEBUG_DBUG='+d,crash_after_log_ibuf_upd_inplace';
|
|
||||||
--exec echo "wait" > $_expect_file_name
|
|
||||||
--error 2013
|
|
||||||
# This should force a change buffer merge
|
|
||||||
SELECT b FROM t1 LIMIT 3;
|
|
||||||
disconnect con1;
|
|
||||||
connection default;
|
|
||||||
let SEARCH_PATTERN=Wrote log record for ibuf update in place operation;
|
|
||||||
--source include/search_pattern_in_file.inc
|
|
||||||
|
|
||||||
--let $restart_parameters= --innodb-read-only
|
|
||||||
--source include/start_mysqld.inc
|
|
||||||
CHECK TABLE t1;
|
|
||||||
--source include/shutdown_mysqld.inc
|
|
||||||
let SEARCH_PATTERN=innodb_read_only prevents crash recovery;
|
|
||||||
--source include/search_pattern_in_file.inc
|
|
||||||
|
|
||||||
--let $restart_parameters= --innodb-force-recovery=5 --debug-dbug=d,crash_after_log_ibuf_upd_inplace
|
|
||||||
--source include/start_mysqld.inc
|
|
||||||
SELECT * FROM t1 LIMIT 1;
|
|
||||||
# Slow shutdown will not merge the changes due to innodb_force_recovery=5.
|
|
||||||
SET GLOBAL innodb_fast_shutdown=0;
|
|
||||||
--let $restart_parameters=
|
|
||||||
--source include/restart_mysqld.inc
|
|
||||||
CHECK TABLE t1;
|
|
||||||
DROP TABLE t1;
|
|
@@ -1 +0,0 @@
|
|||||||
--innodb-sys-tablestats
|
|
@@ -1,519 +0,0 @@
|
|||||||
#
|
|
||||||
# WL#6326: InnoDB: fix index->lock contention
|
|
||||||
#
|
|
||||||
|
|
||||||
--source include/have_innodb.inc
|
|
||||||
--source include/have_debug.inc
|
|
||||||
--source include/have_debug_sync.inc
|
|
||||||
--source include/have_innodb_16k.inc
|
|
||||||
|
|
||||||
--disable_query_log
|
|
||||||
SET @old_innodb_limit_optimistic_insert_debug = @@innodb_limit_optimistic_insert_debug;
|
|
||||||
SET @old_innodb_adaptive_hash_index = @@innodb_adaptive_hash_index;
|
|
||||||
SET @old_innodb_stats_persistent = @@innodb_stats_persistent;
|
|
||||||
--enable_query_log
|
|
||||||
|
|
||||||
# Save the initial number of concurrent sessions
|
|
||||||
--source include/count_sessions.inc
|
|
||||||
|
|
||||||
SET GLOBAL innodb_adaptive_hash_index = false;
|
|
||||||
SET GLOBAL innodb_stats_persistent = false;
|
|
||||||
|
|
||||||
--connect (con1,localhost,root,,)
|
|
||||||
--connect (con2,localhost,root,,)
|
|
||||||
--connect (con3,localhost,root,,)
|
|
||||||
|
|
||||||
CREATE TABLE t1 (
|
|
||||||
a00 CHAR(255) NOT NULL DEFAULT 'a',
|
|
||||||
a01 CHAR(255) NOT NULL DEFAULT 'a',
|
|
||||||
a02 CHAR(255) NOT NULL DEFAULT 'a',
|
|
||||||
a03 CHAR(255) NOT NULL DEFAULT 'a',
|
|
||||||
a04 CHAR(255) NOT NULL DEFAULT 'a',
|
|
||||||
a05 CHAR(255) NOT NULL DEFAULT 'a',
|
|
||||||
a06 CHAR(255) NOT NULL DEFAULT 'a',
|
|
||||||
b INT NOT NULL DEFAULT 0
|
|
||||||
) ENGINE = InnoDB;
|
|
||||||
|
|
||||||
ALTER TABLE t1 ADD PRIMARY KEY(
|
|
||||||
a00,
|
|
||||||
a01,
|
|
||||||
a02,
|
|
||||||
a03,
|
|
||||||
a04,
|
|
||||||
a05,
|
|
||||||
a06
|
|
||||||
);
|
|
||||||
|
|
||||||
#
|
|
||||||
# Prepare primary key index tree to be used for this test.
|
|
||||||
#
|
|
||||||
|
|
||||||
# Only root (1)
|
|
||||||
ANALYZE TABLE t1;
|
|
||||||
SELECT CLUST_INDEX_SIZE FROM information_schema.INNODB_SYS_TABLESTATS WHERE NAME = 'test/t1';
|
|
||||||
|
|
||||||
# Make the first records sparse artificially,
|
|
||||||
# not to cause modify_tree by single node_ptr insert operation.
|
|
||||||
# * (7 - 2) records should be larger than a half of the page size
|
|
||||||
# * (7 + 2) records should be fit to the page
|
|
||||||
# (above t1 definition is already adjusted)
|
|
||||||
SET GLOBAL innodb_limit_optimistic_insert_debug = 7;
|
|
||||||
|
|
||||||
BEGIN;
|
|
||||||
INSERT INTO t1 (a00) VALUES ('aa');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('ab');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('ac');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('ad');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('ae');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('af');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('ag');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('ah');
|
|
||||||
COMMIT;
|
|
||||||
# Raise root (1-2)
|
|
||||||
# (aa,ad)
|
|
||||||
# (aa,ab,ac)(ad,ae,af,ag,ah)
|
|
||||||
ANALYZE TABLE t1;
|
|
||||||
SELECT CLUST_INDEX_SIZE FROM information_schema.INNODB_SYS_TABLESTATS WHERE NAME = 'test/t1';
|
|
||||||
|
|
||||||
BEGIN;
|
|
||||||
INSERT INTO t1 (a00) VALUES ('ai');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('aj');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('ak');
|
|
||||||
COMMIT;
|
|
||||||
# Split leaf (1-3)
|
|
||||||
# (aa,ad,ak)
|
|
||||||
# (aa,ab,ac)(ad,ae,af,ag,ah,ai,aj)(ak)
|
|
||||||
ANALYZE TABLE t1;
|
|
||||||
SELECT CLUST_INDEX_SIZE FROM information_schema.INNODB_SYS_TABLESTATS WHERE NAME = 'test/t1';
|
|
||||||
|
|
||||||
BEGIN;
|
|
||||||
INSERT INTO t1 (a00) VALUES ('al');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('am');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('an');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('ao');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('ap');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('aq');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('ar');
|
|
||||||
COMMIT;
|
|
||||||
# Split leaf (1-4)
|
|
||||||
# (aa,ad,ak,ar)
|
|
||||||
# (aa,ab,ac)(ad,ae,af,ag,ah,ai,aj)(ak,al,am,an,ao,ap,aq)(ar)
|
|
||||||
ANALYZE TABLE t1;
|
|
||||||
SELECT CLUST_INDEX_SIZE FROM information_schema.INNODB_SYS_TABLESTATS WHERE NAME = 'test/t1';
|
|
||||||
|
|
||||||
BEGIN;
|
|
||||||
INSERT INTO t1 (a00) VALUES ('as');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('at');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('au');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('av');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('aw');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('ax');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('ay');
|
|
||||||
COMMIT;
|
|
||||||
# Split leaf (1-5)
|
|
||||||
# (aa,ad,ak,ar,ay)
|
|
||||||
# (aa,ab,ac)(ad,ae,af,ag,ah,ai,aj)(ak,al,am,an,ao,ap,aq)(ar,as,at,au,av,aw,ax)(ay)
|
|
||||||
ANALYZE TABLE t1;
|
|
||||||
SELECT CLUST_INDEX_SIZE FROM information_schema.INNODB_SYS_TABLESTATS WHERE NAME = 'test/t1';
|
|
||||||
|
|
||||||
BEGIN;
|
|
||||||
INSERT INTO t1 (a00) VALUES ('az');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('ba');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('bb');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('bc');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('bd');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('be');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('bf');
|
|
||||||
COMMIT;
|
|
||||||
# Split leaf (1-6)
|
|
||||||
# (aa,ad,ak,ar,ay,bf)
|
|
||||||
# (aa,ab,ac)(ad..)(ak..)(ar,as,at,au,av,aw,ax)(ay,az,ba,bb,bc,bd,be)(bf)
|
|
||||||
ANALYZE TABLE t1;
|
|
||||||
SELECT CLUST_INDEX_SIZE FROM information_schema.INNODB_SYS_TABLESTATS WHERE NAME = 'test/t1';
|
|
||||||
|
|
||||||
BEGIN;
|
|
||||||
INSERT INTO t1 (a00) VALUES ('bg');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('bh');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('bi');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('bj');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('bk');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('bl');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('bm');
|
|
||||||
COMMIT;
|
|
||||||
# Split leaf (1-7)
|
|
||||||
# (aa,ad,ak,ar,ay,bf,bm)
|
|
||||||
# (aa,ab,ac)(ad..)(ak..)(ar..)(ay,az,ba,bb,bc,bd,be)(bf,bg,bh,bi,bj,bk,bl)(bm)
|
|
||||||
ANALYZE TABLE t1;
|
|
||||||
SELECT CLUST_INDEX_SIZE FROM information_schema.INNODB_SYS_TABLESTATS WHERE NAME = 'test/t1';
|
|
||||||
|
|
||||||
BEGIN;
|
|
||||||
INSERT INTO t1 (a00) VALUES ('bn');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('bo');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('bp');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('bq');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('br');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('bs');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('bt');
|
|
||||||
COMMIT;
|
|
||||||
# Raise root (1-2-8)
|
|
||||||
# (aa,ar)
|
|
||||||
# (aa,ad,ak) (ar,ay,bf,bm,bt)
|
|
||||||
# (aa,ab,ac)(ad..)(ak..)(ar..)(ay..)(bf..)(bm..)(bt)
|
|
||||||
ANALYZE TABLE t1;
|
|
||||||
SELECT CLUST_INDEX_SIZE FROM information_schema.INNODB_SYS_TABLESTATS WHERE NAME = 'test/t1';
|
|
||||||
|
|
||||||
BEGIN;
|
|
||||||
INSERT INTO t1 (a00) VALUES ('bu');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('bv');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('bw');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('bx');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('by');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('bz');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('ca');
|
|
||||||
|
|
||||||
INSERT INTO t1 (a00) VALUES ('cb');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('cc');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('cd');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('ce');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('cf');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('cg');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('ch');
|
|
||||||
|
|
||||||
INSERT INTO t1 (a00) VALUES ('ci');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('cj');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('ck');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('cl');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('cm');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('cn');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('co');
|
|
||||||
COMMIT;
|
|
||||||
# Split also at level 1 (1-3-11)
|
|
||||||
# (aa,ar,co)
|
|
||||||
# (aa,ad,ak) (ar,ay,bf,bm,bt,ca,ch) (co)
|
|
||||||
# (aa,ab,ac)(ad..)(ak..)(ar..)(ay..)(bf..)(bm..)(bt..)(ca..)(ch..)(co)
|
|
||||||
ANALYZE TABLE t1;
|
|
||||||
SELECT CLUST_INDEX_SIZE FROM information_schema.INNODB_SYS_TABLESTATS WHERE NAME = 'test/t1';
|
|
||||||
|
|
||||||
BEGIN;
|
|
||||||
INSERT INTO t1 (a00) VALUES ('cp');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('cq');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('cr');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('cs');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('ct');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('cu');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('cv');
|
|
||||||
|
|
||||||
INSERT INTO t1 (a00) VALUES ('cw');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('cx');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('cy');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('cz');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('da');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('db');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('dc');
|
|
||||||
|
|
||||||
INSERT INTO t1 (a00) VALUES ('dd');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('de');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('df');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('dg');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('dh');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('di');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('dj');
|
|
||||||
|
|
||||||
INSERT INTO t1 (a00) VALUES ('dk');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('dl');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('dm');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('dn');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('do');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('dp');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('dq');
|
|
||||||
|
|
||||||
INSERT INTO t1 (a00) VALUES ('dr');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('ds');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('dt');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('du');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('dv');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('dw');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('dx');
|
|
||||||
|
|
||||||
INSERT INTO t1 (a00) VALUES ('dy');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('dz');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('ea');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('eb');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('ec');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('ed');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('ee');
|
|
||||||
|
|
||||||
INSERT INTO t1 (a00) VALUES ('ef');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('eg');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('eh');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('ei');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('ej');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('ek');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('el');
|
|
||||||
COMMIT;
|
|
||||||
# Split also at level 1 (1-4-18)
|
|
||||||
# (aa,ar,co,el)
|
|
||||||
# (aa,ad,ak) (ar,ay,bf,bm,bt,ca,ch) (co,cv,dc,dj,dq,dx,ee) (el)
|
|
||||||
# (aa,ab,ac)(ad..)(ak..)(ar..)(ay..)(bf..)(bm..)(bt..)(ca..)(ch..)(co..)(cv..)(dc..)(dj..)(dq..)(dx..)(ee..)(el)
|
|
||||||
ANALYZE TABLE t1;
|
|
||||||
SELECT CLUST_INDEX_SIZE FROM information_schema.INNODB_SYS_TABLESTATS WHERE NAME = 'test/t1';
|
|
||||||
|
|
||||||
BEGIN;
|
|
||||||
INSERT INTO t1 (a00) VALUES ('em');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('en');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('eo');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('ep');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('eq');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('er');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('es');
|
|
||||||
|
|
||||||
INSERT INTO t1 (a00) VALUES ('et');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('eu');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('ev');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('ew');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('ex');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('ey');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('ez');
|
|
||||||
|
|
||||||
INSERT INTO t1 (a00) VALUES ('fa');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('fb');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('fc');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('fd');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('fe');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('ff');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('fg');
|
|
||||||
|
|
||||||
INSERT INTO t1 (a00) VALUES ('fh');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('fi');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('fj');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('fk');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('fl');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('fm');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('fn');
|
|
||||||
|
|
||||||
INSERT INTO t1 (a00) VALUES ('fo');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('fp');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('fq');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('fr');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('fs');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('ft');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('fu');
|
|
||||||
|
|
||||||
INSERT INTO t1 (a00) VALUES ('fv');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('fw');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('fx');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('fy');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('fz');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('ga');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('gb');
|
|
||||||
|
|
||||||
INSERT INTO t1 (a00) VALUES ('gc');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('gd');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('ge');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('gf');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('gg');
|
|
||||||
INSERT INTO t1 (a00) VALUES ('gh');
|
|
||||||
COMMIT;
|
|
||||||
|
|
||||||
# Current tree form (1-4-24)
|
|
||||||
# (aa,ar,co,el)
|
|
||||||
# (aa,ad,ak) (ar,ay,bf,bm,bt,ca,ch) (co,cv,dc,dj,dq,dx,ee) (el..,gb)
|
|
||||||
# (aa,ab,ac)(ad..)(ak..)(ar..)(ay..)(bf..)(bm..)(bt..)(ca..)(ch..)(co..)(cv..)(dc..)(dj..)(dq..)(dx..)(ee..)(el..)..(gb..)
|
|
||||||
ANALYZE TABLE t1;
|
|
||||||
SELECT CLUST_INDEX_SIZE FROM information_schema.INNODB_SYS_TABLESTATS WHERE NAME = 'test/t1';
|
|
||||||
|
|
||||||
# Insert the rest of records normally
|
|
||||||
SET GLOBAL innodb_limit_optimistic_insert_debug = 0;
|
|
||||||
|
|
||||||
--echo # Test start
|
|
||||||
|
|
||||||
# (1) Insert records to leaf page (bf..) and cause modify_page.
|
|
||||||
# - root page is not X latched
|
|
||||||
# - latched from level 1 page (ar,ay,bf,bm,bt,ca,ch)
|
|
||||||
|
|
||||||
SET DEBUG_SYNC = 'RESET';
|
|
||||||
|
|
||||||
# Filling leaf page (bf..)
|
|
||||||
INSERT INTO t1 (a00) VALUES ('bfa');
|
|
||||||
|
|
||||||
--connection con1
|
|
||||||
SET DEBUG_SYNC = 'before_insert_pessimitic_row_ins_clust SIGNAL reached WAIT_FOR continue';
|
|
||||||
# Cause modify_tree
|
|
||||||
--send
|
|
||||||
INSERT INTO t1 (a00) VALUES ('bfb');
|
|
||||||
|
|
||||||
--connection con2
|
|
||||||
SET DEBUG_SYNC = 'now WAIT_FOR reached';
|
|
||||||
# Not blocked searches
|
|
||||||
SELECT a00,a01 FROM t1 WHERE a00 = 'aa';
|
|
||||||
SELECT a00,a01 FROM t1 WHERE a00 = 'aq';
|
|
||||||
# "where a00 = 'co'" is blocked because searching from smaller ('co','a','a',..).
|
|
||||||
SELECT a00,a01 FROM t1 WHERE a00 = 'cp';
|
|
||||||
SELECT a00,a01 FROM t1 WHERE a00 = 'el';
|
|
||||||
|
|
||||||
SET DEBUG_SYNC = 'rw_s_lock_waiting SIGNAL lockwait1';
|
|
||||||
# Blocked
|
|
||||||
--send
|
|
||||||
SELECT a00,a01 FROM t1 WHERE a00 = 'ar';
|
|
||||||
|
|
||||||
--connection con3
|
|
||||||
SET DEBUG_SYNC = 'rw_s_lock_waiting SIGNAL lockwait2';
|
|
||||||
# Blocked
|
|
||||||
--send
|
|
||||||
SELECT a00,a01 FROM t1 WHERE a00 = 'cn';
|
|
||||||
|
|
||||||
--connection default
|
|
||||||
# FIXME: These occasionally time out!
|
|
||||||
--disable_warnings
|
|
||||||
SET DEBUG_SYNC = 'now WAIT_FOR lockwait1 TIMEOUT 1';
|
|
||||||
SET DEBUG_SYNC = 'now WAIT_FOR lockwait2 TIMEOUT 1';
|
|
||||||
--enable_warnings
|
|
||||||
SET DEBUG_SYNC = 'now SIGNAL continue';
|
|
||||||
|
|
||||||
--connection con1
|
|
||||||
--reap
|
|
||||||
|
|
||||||
--connection con2
|
|
||||||
--reap
|
|
||||||
|
|
||||||
--connection con3
|
|
||||||
--reap
|
|
||||||
|
|
||||||
--connection default
|
|
||||||
|
|
||||||
ANALYZE TABLE t1;
|
|
||||||
SELECT CLUST_INDEX_SIZE FROM information_schema.INNODB_SYS_TABLESTATS WHERE NAME = 'test/t1';
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# (2) Insert records to leaf page (co..) and cause modify_page
|
|
||||||
# - root page is X latched, because node_ptr for 'co'
|
|
||||||
# is 1st record for (co,cv,dc,dj,dq,dx,ee)
|
|
||||||
#
|
|
||||||
# * ordinary pessimitic insert might be done by pessistic update
|
|
||||||
# and we should consider possibility node_ptr to be deleted.
|
|
||||||
|
|
||||||
SET DEBUG_SYNC = 'RESET';
|
|
||||||
|
|
||||||
# Filling leaf page (co..)
|
|
||||||
INSERT INTO t1 (a00) VALUES ('coa');
|
|
||||||
|
|
||||||
--connection con1
|
|
||||||
SET DEBUG_SYNC = 'before_insert_pessimitic_row_ins_clust SIGNAL reached WAIT_FOR continue';
|
|
||||||
# Cause modify_tree
|
|
||||||
--send
|
|
||||||
INSERT INTO t1 (a00) VALUES ('cob');
|
|
||||||
|
|
||||||
--connection con2
|
|
||||||
SET DEBUG_SYNC = 'now WAIT_FOR reached';
|
|
||||||
# All searches are blocked because root page is X latched
|
|
||||||
|
|
||||||
SET DEBUG_SYNC = 'rw_s_lock_waiting SIGNAL lockwait1';
|
|
||||||
# Blocked
|
|
||||||
--send
|
|
||||||
SELECT a00,a01 FROM t1 WHERE a00 = 'aa';
|
|
||||||
|
|
||||||
--connection con3
|
|
||||||
SET DEBUG_SYNC = 'rw_s_lock_waiting SIGNAL lockwait2';
|
|
||||||
# Blocked
|
|
||||||
--send
|
|
||||||
SELECT a00,a01 FROM t1 WHERE a00 = 'el';
|
|
||||||
|
|
||||||
--connection default
|
|
||||||
# FIXME: These occasionally time out!
|
|
||||||
--disable_warnings
|
|
||||||
SET DEBUG_SYNC = 'now WAIT_FOR lockwait1 TIMEOUT 1';
|
|
||||||
SET DEBUG_SYNC = 'now WAIT_FOR lockwait2 TIMEOUT 1';
|
|
||||||
--enable_warnings
|
|
||||||
SET DEBUG_SYNC = 'now SIGNAL continue';
|
|
||||||
|
|
||||||
--connection con1
|
|
||||||
--reap
|
|
||||||
|
|
||||||
--connection con2
|
|
||||||
--reap
|
|
||||||
|
|
||||||
--connection con3
|
|
||||||
--reap
|
|
||||||
|
|
||||||
--connection default
|
|
||||||
|
|
||||||
ANALYZE TABLE t1;
|
|
||||||
SELECT CLUST_INDEX_SIZE FROM information_schema.INNODB_SYS_TABLESTATS WHERE NAME = 'test/t1';
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# (3) Insert records to rightmost leaf page (gb..) and cause modify_page
|
|
||||||
# - root page is not X latched, because node_ptr for 'gb' is the last record
|
|
||||||
# of the level 1 though it is last record in the page.
|
|
||||||
# - lathed from level 1 page (el..,gb)
|
|
||||||
|
|
||||||
SET DEBUG_SYNC = 'RESET';
|
|
||||||
|
|
||||||
# Filling leaf page (gb..)
|
|
||||||
INSERT INTO t1 (a00) VALUES ('gba');
|
|
||||||
|
|
||||||
--connection con1
|
|
||||||
SET DEBUG_SYNC = 'before_insert_pessimitic_row_ins_clust SIGNAL reached WAIT_FOR continue';
|
|
||||||
# Cause modify_tree
|
|
||||||
--send
|
|
||||||
INSERT INTO t1 (a00) VALUES ('gbb');
|
|
||||||
|
|
||||||
--connection con2
|
|
||||||
SET DEBUG_SYNC = 'now WAIT_FOR reached';
|
|
||||||
# Not blocked searches
|
|
||||||
SELECT a00,a01 FROM t1 WHERE a00 = 'aa';
|
|
||||||
SELECT a00,a01 FROM t1 WHERE a00 = 'ek';
|
|
||||||
|
|
||||||
SET DEBUG_SYNC = 'rw_s_lock_waiting SIGNAL lockwait1';
|
|
||||||
# Blocked
|
|
||||||
--send
|
|
||||||
SELECT a00,a01 FROM t1 WHERE a00 = 'el';
|
|
||||||
|
|
||||||
--connection con3
|
|
||||||
SET DEBUG_SYNC = 'rw_s_lock_waiting SIGNAL lockwait2';
|
|
||||||
# Blocked
|
|
||||||
--send
|
|
||||||
SELECT a00,a01 FROM t1 WHERE a00 = 'gb';
|
|
||||||
|
|
||||||
--connection default
|
|
||||||
# FIXME: These occasionally time out!
|
|
||||||
--disable_warnings
|
|
||||||
SET DEBUG_SYNC = 'now WAIT_FOR lockwait1 TIMEOUT 1';
|
|
||||||
SET DEBUG_SYNC = 'now WAIT_FOR lockwait2 TIMEOUT 1';
|
|
||||||
--enable_warnings
|
|
||||||
SET DEBUG_SYNC = 'now SIGNAL continue';
|
|
||||||
|
|
||||||
--connection con1
|
|
||||||
--reap
|
|
||||||
|
|
||||||
--connection con2
|
|
||||||
--reap
|
|
||||||
|
|
||||||
--connection con3
|
|
||||||
--reap
|
|
||||||
|
|
||||||
--connection default
|
|
||||||
ANALYZE TABLE t1;
|
|
||||||
SELECT CLUST_INDEX_SIZE FROM information_schema.INNODB_SYS_TABLESTATS WHERE NAME = 'test/t1';
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Cleanup
|
|
||||||
SET DEBUG_SYNC = 'RESET';
|
|
||||||
|
|
||||||
--connection default
|
|
||||||
--disconnect con1
|
|
||||||
--disconnect con2
|
|
||||||
--disconnect con3
|
|
||||||
|
|
||||||
DROP TABLE t1;
|
|
||||||
|
|
||||||
--disable_query_log
|
|
||||||
SET GLOBAL innodb_limit_optimistic_insert_debug = @old_innodb_limit_optimistic_insert_debug;
|
|
||||||
SET GLOBAL innodb_adaptive_hash_index = @old_innodb_adaptive_hash_index;
|
|
||||||
SET GLOBAL innodb_stats_persistent = @old_innodb_stats_persistent;
|
|
||||||
--enable_query_log
|
|
||||||
|
|
||||||
# Wait till all disconnects are completed.
|
|
||||||
--source include/wait_until_count_sessions.inc
|
|
@@ -51,6 +51,10 @@ SET tx_read_only=1;
|
|||||||
BEGIN;
|
BEGIN;
|
||||||
INSERT INTO t2 VALUES(0);
|
INSERT INTO t2 VALUES(0);
|
||||||
INSERT INTO t VALUES(0);
|
INSERT INTO t VALUES(0);
|
||||||
|
ROLLBACK;
|
||||||
|
BEGIN;
|
||||||
|
INSERT INTO t2 VALUES(0);
|
||||||
|
INSERT INTO t VALUES(0);
|
||||||
COMMIT;
|
COMMIT;
|
||||||
INSERT INTO t VALUES(0);
|
INSERT INTO t VALUES(0);
|
||||||
|
|
||||||
|
@@ -1 +1,2 @@
|
|||||||
--innodb-buffer-pool-size=24M
|
--innodb-buffer-pool-size=24M
|
||||||
|
--innodb-immediate-scrub-data-uncompressed=ON
|
||||||
|
@@ -61,3 +61,15 @@ select count(*) from t1 where MBRWithin(t1.c2, @g1);
|
|||||||
count(*)
|
count(*)
|
||||||
57344
|
57344
|
||||||
drop table t1;
|
drop table t1;
|
||||||
|
#
|
||||||
|
# MDEV-30400 Assertion height == btr_page_get_level ... on INSERT
|
||||||
|
#
|
||||||
|
CREATE TABLE t1 (c POINT NOT NULL,SPATIAL (c)) ENGINE=InnoDB;
|
||||||
|
SET @save_limit=@@GLOBAL.innodb_limit_optimistic_insert_debug;
|
||||||
|
SET GLOBAL innodb_limit_optimistic_insert_debug=2;
|
||||||
|
BEGIN;
|
||||||
|
INSERT INTO t1 SELECT POINTFROMTEXT ('POINT(0 0)') FROM seq_1_to_6;
|
||||||
|
ROLLBACK;
|
||||||
|
SET GLOBAL innodb_limit_optimistic_insert_debug=@save_limit;
|
||||||
|
DROP TABLE t1;
|
||||||
|
# End of 10.6 tests
|
||||||
|
@@ -73,3 +73,18 @@ select count(*) from t1 where MBRWithin(t1.c2, @g1);
|
|||||||
|
|
||||||
# Clean up.
|
# Clean up.
|
||||||
drop table t1;
|
drop table t1;
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # MDEV-30400 Assertion height == btr_page_get_level ... on INSERT
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
CREATE TABLE t1 (c POINT NOT NULL,SPATIAL (c)) ENGINE=InnoDB;
|
||||||
|
SET @save_limit=@@GLOBAL.innodb_limit_optimistic_insert_debug;
|
||||||
|
SET GLOBAL innodb_limit_optimistic_insert_debug=2;
|
||||||
|
BEGIN;
|
||||||
|
INSERT INTO t1 SELECT POINTFROMTEXT ('POINT(0 0)') FROM seq_1_to_6;
|
||||||
|
ROLLBACK;
|
||||||
|
SET GLOBAL innodb_limit_optimistic_insert_debug=@save_limit;
|
||||||
|
DROP TABLE t1;
|
||||||
|
|
||||||
|
--echo # End of 10.6 tests
|
||||||
|
@@ -24,7 +24,7 @@ PLUGIN_TYPE DATA TYPE
|
|||||||
PLUGIN_AUTHOR MariaDB Corporation
|
PLUGIN_AUTHOR MariaDB Corporation
|
||||||
PLUGIN_DESCRIPTION Data type INET4
|
PLUGIN_DESCRIPTION Data type INET4
|
||||||
PLUGIN_LICENSE GPL
|
PLUGIN_LICENSE GPL
|
||||||
PLUGIN_MATURITY Alpha
|
PLUGIN_MATURITY Gamma
|
||||||
PLUGIN_AUTH_VERSION 1.0
|
PLUGIN_AUTH_VERSION 1.0
|
||||||
#
|
#
|
||||||
# End of 10.10 tests
|
# End of 10.10 tests
|
||||||
|
@@ -189,7 +189,7 @@ maria_declare_plugin(type_inet)
|
|||||||
NULL, // Status variables
|
NULL, // Status variables
|
||||||
NULL, // System variables
|
NULL, // System variables
|
||||||
"1.0", // String version representation
|
"1.0", // String version representation
|
||||||
MariaDB_PLUGIN_MATURITY_ALPHA // Maturity(see include/mysql/plugin.h)*/
|
MariaDB_PLUGIN_MATURITY_GAMMA // Maturity(see include/mysql/plugin.h)*/
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
MariaDB_DATA_TYPE_PLUGIN, // the plugin type (see include/mysql/plugin.h)
|
MariaDB_DATA_TYPE_PLUGIN, // the plugin type (see include/mysql/plugin.h)
|
||||||
|
File diff suppressed because one or more lines are too long
@@ -238,7 +238,7 @@ extern "C" my_bool wsrep_thd_bf_abort(THD *bf_thd, THD *victim_thd,
|
|||||||
}
|
}
|
||||||
|
|
||||||
victim_thd->wsrep_aborter= bf_thd->thread_id;
|
victim_thd->wsrep_aborter= bf_thd->thread_id;
|
||||||
victim_thd->awake_no_mutex(KILL_QUERY);
|
victim_thd->awake_no_mutex(KILL_QUERY_HARD);
|
||||||
mysql_mutex_unlock(&victim_thd->LOCK_thd_data);
|
mysql_mutex_unlock(&victim_thd->LOCK_thd_data);
|
||||||
} else {
|
} else {
|
||||||
WSREP_DEBUG("wsrep_thd_bf_abort skipped awake, signal %d", signal);
|
WSREP_DEBUG("wsrep_thd_bf_abort skipped awake, signal %d", signal);
|
||||||
@@ -417,3 +417,23 @@ extern "C" void wsrep_thd_set_PA_unsafe(THD *thd)
|
|||||||
WSREP_DEBUG("session does not have active transaction, can not mark as PA unsafe");
|
WSREP_DEBUG("session does not have active transaction, can not mark as PA unsafe");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern "C" int wsrep_thd_append_table_key(MYSQL_THD thd,
|
||||||
|
const char* db,
|
||||||
|
const char* table,
|
||||||
|
enum Wsrep_service_key_type key_type)
|
||||||
|
{
|
||||||
|
wsrep_key_arr_t key_arr = {0, 0};
|
||||||
|
int ret = wsrep_prepare_keys_for_isolation(thd, db, table, NULL, &key_arr);
|
||||||
|
ret = ret || wsrep_thd_append_key(thd, key_arr.keys,
|
||||||
|
(int)key_arr.keys_len, key_type);
|
||||||
|
wsrep_keys_free(&key_arr);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" my_bool wsrep_thd_is_local_transaction(const THD *thd)
|
||||||
|
{
|
||||||
|
return (wsrep_thd_is_local(thd) &&
|
||||||
|
thd->wsrep_cs().transaction().active());
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -1520,7 +1520,7 @@ sp_head::execute(THD *thd, bool merge_da_on_success)
|
|||||||
wsrep_current_error_status(thd));
|
wsrep_current_error_status(thd));
|
||||||
thd->wsrep_cs().reset_error();
|
thd->wsrep_cs().reset_error();
|
||||||
/* Reset also thd->killed if it has been set during BF abort. */
|
/* Reset also thd->killed if it has been set during BF abort. */
|
||||||
if (thd->killed == KILL_QUERY)
|
if (killed_mask_hard(thd->killed) == KILL_QUERY)
|
||||||
thd->killed= NOT_KILLED;
|
thd->killed= NOT_KILLED;
|
||||||
/* if failed transaction was not replayed, must return with error from here */
|
/* if failed transaction was not replayed, must return with error from here */
|
||||||
if (!must_replay) err_status = 1;
|
if (!must_replay) err_status = 1;
|
||||||
|
@@ -162,6 +162,8 @@ static struct wsrep_service_st wsrep_handler = {
|
|||||||
wsrep_thd_is_local,
|
wsrep_thd_is_local,
|
||||||
wsrep_thd_self_abort,
|
wsrep_thd_self_abort,
|
||||||
wsrep_thd_append_key,
|
wsrep_thd_append_key,
|
||||||
|
wsrep_thd_append_table_key,
|
||||||
|
wsrep_thd_is_local_transaction,
|
||||||
wsrep_thd_client_state_str,
|
wsrep_thd_client_state_str,
|
||||||
wsrep_thd_client_mode_str,
|
wsrep_thd_client_mode_str,
|
||||||
wsrep_thd_transaction_state_str,
|
wsrep_thd_transaction_state_str,
|
||||||
|
@@ -101,6 +101,12 @@ void wsrep_thd_self_abort(THD *)
|
|||||||
int wsrep_thd_append_key(THD *, const struct wsrep_key*, int, enum Wsrep_service_key_type)
|
int wsrep_thd_append_key(THD *, const struct wsrep_key*, int, enum Wsrep_service_key_type)
|
||||||
{ return 0; }
|
{ return 0; }
|
||||||
|
|
||||||
|
int wsrep_thd_append_table_key(THD *, const char*, const char*, enum Wsrep_service_key_type)
|
||||||
|
{ return 0; }
|
||||||
|
|
||||||
|
my_bool wsrep_thd_is_local_transaction(const THD*)
|
||||||
|
{ return 0; }
|
||||||
|
|
||||||
const char* wsrep_thd_client_state_str(const THD*)
|
const char* wsrep_thd_client_state_str(const THD*)
|
||||||
{ return 0; }
|
{ return 0; }
|
||||||
|
|
||||||
|
@@ -332,12 +332,14 @@ SET(INNOBASE_SOURCES
|
|||||||
include/row0upd.inl
|
include/row0upd.inl
|
||||||
include/row0vers.h
|
include/row0vers.h
|
||||||
include/rw_lock.h
|
include/rw_lock.h
|
||||||
|
include/small_vector.h
|
||||||
include/srv0mon.h
|
include/srv0mon.h
|
||||||
include/srv0mon.inl
|
include/srv0mon.inl
|
||||||
include/srv0srv.h
|
include/srv0srv.h
|
||||||
include/srv0start.h
|
include/srv0start.h
|
||||||
include/srw_lock.h
|
include/srw_lock.h
|
||||||
include/sux_lock.h
|
include/sux_lock.h
|
||||||
|
include/transactional_lock_guard.h
|
||||||
include/trx0i_s.h
|
include/trx0i_s.h
|
||||||
include/trx0purge.h
|
include/trx0purge.h
|
||||||
include/trx0rec.h
|
include/trx0rec.h
|
||||||
|
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
Copyright (c) 1994, 2016, Oracle and/or its affiliates. All Rights Reserved.
|
Copyright (c) 1994, 2016, Oracle and/or its affiliates. All Rights Reserved.
|
||||||
Copyright (c) 2012, Facebook Inc.
|
Copyright (c) 2012, Facebook Inc.
|
||||||
Copyright (c) 2014, 2022, MariaDB Corporation.
|
Copyright (c) 2014, 2023, MariaDB Corporation.
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify it under
|
This program is free software; you can redistribute it and/or modify it under
|
||||||
the terms of the GNU General Public License as published by the Free Software
|
the terms of the GNU General Public License as published by the Free Software
|
||||||
@@ -460,6 +460,54 @@ btr_page_create(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
buf_block_t *
|
||||||
|
mtr_t::get_already_latched(const page_id_t id, mtr_memo_type_t type) const
|
||||||
|
{
|
||||||
|
ut_ad(is_active());
|
||||||
|
ut_ad(type == MTR_MEMO_PAGE_X_FIX || type == MTR_MEMO_PAGE_SX_FIX ||
|
||||||
|
type == MTR_MEMO_PAGE_S_FIX);
|
||||||
|
for (ulint i= 0; i < m_memo.size(); i++)
|
||||||
|
{
|
||||||
|
const mtr_memo_slot_t &slot= m_memo[i];
|
||||||
|
const auto slot_type= mtr_memo_type_t(slot.type & ~MTR_MEMO_MODIFY);
|
||||||
|
if (slot_type == MTR_MEMO_PAGE_X_FIX || slot_type == type)
|
||||||
|
{
|
||||||
|
buf_block_t *block= static_cast<buf_block_t*>(slot.object);
|
||||||
|
if (block->page.id() == id)
|
||||||
|
return block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Fetch an index root page that was already latched in the
|
||||||
|
mini-transaction. */
|
||||||
|
static buf_block_t *btr_get_latched_root(const dict_index_t &index, mtr_t *mtr)
|
||||||
|
{
|
||||||
|
return mtr->get_already_latched(page_id_t{index.table->space_id, index.page},
|
||||||
|
MTR_MEMO_PAGE_SX_FIX);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Fetch an index page that should have been already latched in the
|
||||||
|
mini-transaction. */
|
||||||
|
static buf_block_t *
|
||||||
|
btr_block_reget(mtr_t *mtr, const dict_index_t &index,
|
||||||
|
const page_id_t id, rw_lock_type_t rw_latch,
|
||||||
|
dberr_t *err)
|
||||||
|
{
|
||||||
|
if (buf_block_t *block=
|
||||||
|
mtr->get_already_latched(id, mtr_memo_type_t(rw_latch)))
|
||||||
|
{
|
||||||
|
*err= DB_SUCCESS;
|
||||||
|
return block;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0 /* MDEV-29385 FIXME: Acquire the page latch upfront. */
|
||||||
|
ut_ad(mtr->memo_contains_flagged(&index.lock, MTR_MEMO_X_LOCK));
|
||||||
|
#endif
|
||||||
|
return btr_block_get(index, id.page_no(), rw_latch, true, mtr, err);
|
||||||
|
}
|
||||||
|
|
||||||
/**************************************************************//**
|
/**************************************************************//**
|
||||||
Allocates a new file page to be used in an ibuf tree. Takes the page from
|
Allocates a new file page to be used in an ibuf tree. Takes the page from
|
||||||
the free list of the tree, which must contain pages!
|
the free list of the tree, which must contain pages!
|
||||||
@@ -472,18 +520,16 @@ btr_page_alloc_for_ibuf(
|
|||||||
mtr_t* mtr, /*!< in: mtr */
|
mtr_t* mtr, /*!< in: mtr */
|
||||||
dberr_t* err) /*!< out: error code */
|
dberr_t* err) /*!< out: error code */
|
||||||
{
|
{
|
||||||
buf_block_t *root= btr_root_block_get(index, RW_SX_LATCH, mtr, err);
|
buf_block_t *root= btr_get_latched_root(*index, mtr);
|
||||||
if (UNIV_UNLIKELY(!root))
|
if (UNIV_UNLIKELY(!root))
|
||||||
return root;
|
return root;
|
||||||
|
|
||||||
buf_block_t *new_block=
|
buf_block_t *new_block=
|
||||||
buf_page_get_gen(page_id_t(index->table->space_id,
|
buf_page_get_gen(page_id_t(IBUF_SPACE_ID,
|
||||||
mach_read_from_4(PAGE_HEADER +
|
mach_read_from_4(PAGE_HEADER +
|
||||||
PAGE_BTR_IBUF_FREE_LIST +
|
PAGE_BTR_IBUF_FREE_LIST +
|
||||||
FLST_FIRST + FIL_ADDR_PAGE +
|
FLST_FIRST + FIL_ADDR_PAGE +
|
||||||
root->page.frame)),
|
root->page.frame)),
|
||||||
index->table->space->zip_size(), RW_X_LATCH, nullptr,
|
0, RW_X_LATCH, nullptr, BUF_GET, mtr, err);
|
||||||
BUF_GET, mtr, err);
|
|
||||||
if (new_block)
|
if (new_block)
|
||||||
*err= flst_remove(root, PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST, new_block,
|
*err= flst_remove(root, PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST, new_block,
|
||||||
PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST_NODE, mtr);
|
PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST_NODE, mtr);
|
||||||
@@ -523,11 +569,11 @@ btr_page_alloc_low(
|
|||||||
#ifdef BTR_CUR_HASH_ADAPT
|
#ifdef BTR_CUR_HASH_ADAPT
|
||||||
ut_ad(!root->index || !root->index->freed());
|
ut_ad(!root->index || !root->index->freed());
|
||||||
#endif
|
#endif
|
||||||
mtr->release_block_at_savepoint(savepoint, root);
|
mtr->rollback_to_savepoint(savepoint);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
mtr->u_lock_register(savepoint);
|
mtr->lock_register(savepoint, MTR_MEMO_PAGE_SX_FIX);
|
||||||
root->page.lock.u_lock();
|
root->page.lock.u_lock();
|
||||||
#ifdef BTR_CUR_HASH_ADAPT
|
#ifdef BTR_CUR_HASH_ADAPT
|
||||||
btr_search_drop_page_hash_index(root, true);
|
btr_search_drop_page_hash_index(root, true);
|
||||||
@@ -579,15 +625,12 @@ btr_page_free_for_ibuf(
|
|||||||
mtr_t* mtr) /*!< in: mtr */
|
mtr_t* mtr) /*!< in: mtr */
|
||||||
{
|
{
|
||||||
ut_ad(mtr->memo_contains_flagged(block, MTR_MEMO_PAGE_X_FIX));
|
ut_ad(mtr->memo_contains_flagged(block, MTR_MEMO_PAGE_X_FIX));
|
||||||
|
buf_block_t *root= btr_get_latched_root(*index, mtr);
|
||||||
dberr_t err;
|
dberr_t err=
|
||||||
if (buf_block_t *root= btr_root_block_get(index, RW_SX_LATCH, mtr, &err))
|
flst_add_first(root, PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST,
|
||||||
{
|
|
||||||
err= flst_add_first(root, PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST,
|
|
||||||
block, PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST_NODE, mtr);
|
block, PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST_NODE, mtr);
|
||||||
ut_d(if (err == DB_SUCCESS)
|
ut_d(if (err == DB_SUCCESS)
|
||||||
flst_validate(root, PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST, mtr));
|
flst_validate(root, PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST, mtr));
|
||||||
}
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -637,11 +680,11 @@ dberr_t btr_page_free(dict_index_t* index, buf_block_t* block, mtr_t* mtr,
|
|||||||
#ifdef BTR_CUR_HASH_ADAPT
|
#ifdef BTR_CUR_HASH_ADAPT
|
||||||
ut_ad(!root->index || !root->index->freed());
|
ut_ad(!root->index || !root->index->freed());
|
||||||
#endif
|
#endif
|
||||||
mtr->release_block_at_savepoint(savepoint, root);
|
mtr->rollback_to_savepoint(savepoint);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
mtr->u_lock_register(savepoint);
|
mtr->lock_register(savepoint, MTR_MEMO_PAGE_SX_FIX);
|
||||||
root->page.lock.u_lock();
|
root->page.lock.u_lock();
|
||||||
#ifdef BTR_CUR_HASH_ADAPT
|
#ifdef BTR_CUR_HASH_ADAPT
|
||||||
btr_search_drop_page_hash_index(root, true);
|
btr_search_drop_page_hash_index(root, true);
|
||||||
@@ -712,35 +755,27 @@ btr_node_ptr_get_child(
|
|||||||
mtr, err);
|
mtr, err);
|
||||||
}
|
}
|
||||||
|
|
||||||
MY_ATTRIBUTE((nonnull(2,3,5), warn_unused_result))
|
MY_ATTRIBUTE((nonnull(2,3,4), warn_unused_result))
|
||||||
/************************************************************//**
|
/************************************************************//**
|
||||||
Returns the upper level node pointer to a page. It is assumed that mtr holds
|
Returns the upper level node pointer to a page. It is assumed that mtr holds
|
||||||
an sx-latch on the tree.
|
an sx-latch on the tree.
|
||||||
@return rec_get_offsets() of the node pointer record */
|
@return rec_get_offsets() of the node pointer record */
|
||||||
static
|
static
|
||||||
rec_offs*
|
rec_offs*
|
||||||
btr_page_get_father_node_ptr_func(
|
btr_page_get_father_node_ptr_for_validate(
|
||||||
/*==============================*/
|
|
||||||
rec_offs* offsets,/*!< in: work area for the return value */
|
rec_offs* offsets,/*!< in: work area for the return value */
|
||||||
mem_heap_t* heap, /*!< in: memory heap to use */
|
mem_heap_t* heap, /*!< in: memory heap to use */
|
||||||
btr_cur_t* cursor, /*!< in: cursor pointing to user record,
|
btr_cur_t* cursor, /*!< in: cursor pointing to user record,
|
||||||
out: cursor on node pointer record,
|
out: cursor on node pointer record,
|
||||||
its page x-latched */
|
its page x-latched */
|
||||||
btr_latch_mode latch_mode,/*!< in: BTR_CONT_MODIFY_TREE
|
|
||||||
or BTR_CONT_SEARCH_TREE */
|
|
||||||
mtr_t* mtr) /*!< in: mtr */
|
mtr_t* mtr) /*!< in: mtr */
|
||||||
{
|
{
|
||||||
ut_ad(latch_mode == BTR_CONT_MODIFY_TREE
|
|
||||||
|| latch_mode == BTR_CONT_SEARCH_TREE);
|
|
||||||
|
|
||||||
const uint32_t page_no = btr_cur_get_block(cursor)->page.id().page_no();
|
const uint32_t page_no = btr_cur_get_block(cursor)->page.id().page_no();
|
||||||
dict_index_t* index = btr_cur_get_index(cursor);
|
dict_index_t* index = btr_cur_get_index(cursor);
|
||||||
ut_ad(!dict_index_is_spatial(index));
|
ut_ad(!dict_index_is_spatial(index));
|
||||||
|
|
||||||
ut_ad(srv_read_only_mode
|
ut_ad(mtr->memo_contains_flagged(&index->lock, MTR_MEMO_X_LOCK
|
||||||
|| mtr->memo_contains_flagged(&index->lock, MTR_MEMO_X_LOCK
|
| MTR_MEMO_SX_LOCK));
|
||||||
| MTR_MEMO_SX_LOCK));
|
|
||||||
|
|
||||||
ut_ad(dict_index_get_page(index) != page_no);
|
ut_ad(dict_index_get_page(index) != page_no);
|
||||||
|
|
||||||
const auto level = btr_page_get_level(btr_cur_get_page(cursor));
|
const auto level = btr_page_get_level(btr_cur_get_page(cursor));
|
||||||
@@ -752,12 +787,16 @@ btr_page_get_father_node_ptr_func(
|
|||||||
dict_index_build_node_ptr(index,
|
dict_index_build_node_ptr(index,
|
||||||
user_rec, 0,
|
user_rec, 0,
|
||||||
heap, level),
|
heap, level),
|
||||||
PAGE_CUR_LE, latch_mode,
|
RW_S_LATCH,
|
||||||
cursor, mtr) != DB_SUCCESS) {
|
cursor, mtr) != DB_SUCCESS) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
const rec_t* node_ptr = btr_cur_get_rec(cursor);
|
const rec_t* node_ptr = btr_cur_get_rec(cursor);
|
||||||
|
#if 0 /* MDEV-29835 FIXME */
|
||||||
|
ut_ad(!btr_cur_get_block(cursor)->page.lock.not_recursive()
|
||||||
|
|| mtr->memo_contains(index->lock, MTR_MEMO_X_LOCK));
|
||||||
|
#endif
|
||||||
|
|
||||||
offsets = rec_get_offsets(node_ptr, index, offsets, 0,
|
offsets = rec_get_offsets(node_ptr, index, offsets, 0,
|
||||||
ULINT_UNDEFINED, &heap);
|
ULINT_UNDEFINED, &heap);
|
||||||
@@ -769,13 +808,65 @@ btr_page_get_father_node_ptr_func(
|
|||||||
return(offsets);
|
return(offsets);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define btr_page_get_father_node_ptr(of,heap,cur,mtr) \
|
MY_ATTRIBUTE((nonnull(2,3,4), warn_unused_result))
|
||||||
btr_page_get_father_node_ptr_func( \
|
/** Return the node pointer to a page.
|
||||||
of,heap,cur,BTR_CONT_MODIFY_TREE,mtr)
|
@param offsets work area for the return value
|
||||||
|
@param heap memory heap
|
||||||
|
@param cursor in: child page; out: node pointer to it
|
||||||
|
@param mtr mini-transaction
|
||||||
|
@return rec_get_offsets() of the node pointer record
|
||||||
|
@retval nullptr if the parent page had not been latched in mtr */
|
||||||
|
static rec_offs *btr_page_get_parent(rec_offs *offsets, mem_heap_t *heap,
|
||||||
|
btr_cur_t *cursor, mtr_t *mtr)
|
||||||
|
{
|
||||||
|
const uint32_t page_no= cursor->block()->page.id().page_no();
|
||||||
|
const dict_index_t *index= cursor->index();
|
||||||
|
ut_ad(!index->is_spatial());
|
||||||
|
ut_ad(index->page != page_no);
|
||||||
|
|
||||||
#define btr_page_get_father_node_ptr_for_validate(of,heap,cur,mtr) \
|
uint32_t p= index->page;
|
||||||
btr_page_get_father_node_ptr_func( \
|
auto level= btr_page_get_level(cursor->block()->page.frame);
|
||||||
of,heap,cur,BTR_CONT_SEARCH_TREE,mtr)
|
const dtuple_t *tuple=
|
||||||
|
dict_index_build_node_ptr(index, btr_cur_get_rec(cursor), 0, heap, level);
|
||||||
|
level++;
|
||||||
|
|
||||||
|
ulint i;
|
||||||
|
for (i= 0; i < mtr->get_savepoint(); i++)
|
||||||
|
if (buf_block_t *block= mtr->block_at_savepoint(i))
|
||||||
|
if (block->page.id().page_no() == p)
|
||||||
|
{
|
||||||
|
ut_ad(block->page.lock.have_u_or_x() ||
|
||||||
|
(!block->page.lock.have_s() && index->lock.have_x()));
|
||||||
|
ulint up_match= 0, low_match= 0;
|
||||||
|
cursor->page_cur.block= block;
|
||||||
|
if (page_cur_search_with_match(tuple, PAGE_CUR_LE, &up_match,
|
||||||
|
&low_match, &cursor->page_cur,
|
||||||
|
nullptr))
|
||||||
|
return nullptr;
|
||||||
|
offsets= rec_get_offsets(cursor->page_cur.rec, index, offsets, 0,
|
||||||
|
ULINT_UNDEFINED, &heap);
|
||||||
|
p= btr_node_ptr_get_child_page_no(cursor->page_cur.rec, offsets);
|
||||||
|
if (p != page_no)
|
||||||
|
{
|
||||||
|
if (btr_page_get_level(block->page.frame) == level)
|
||||||
|
return nullptr;
|
||||||
|
i= 0; // MDEV-29835 FIXME: require all pages to be latched in order!
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
ut_ad(block->page.lock.have_u_or_x());
|
||||||
|
if (block->page.lock.have_u_not_x())
|
||||||
|
{
|
||||||
|
/* btr_cur_t::search_leaf(BTR_MODIFY_TREE) only U-latches the
|
||||||
|
root page initially. */
|
||||||
|
ut_ad(block->page.id().page_no() == index->page);
|
||||||
|
block->page.lock.u_x_upgrade();
|
||||||
|
mtr->page_lock_upgrade(*block);
|
||||||
|
}
|
||||||
|
return offsets;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
/************************************************************//**
|
/************************************************************//**
|
||||||
Returns the upper level node pointer to a page. It is assumed that mtr holds
|
Returns the upper level node pointer to a page. It is assumed that mtr holds
|
||||||
@@ -796,7 +887,7 @@ btr_page_get_father_block(
|
|||||||
if (UNIV_UNLIKELY(!rec))
|
if (UNIV_UNLIKELY(!rec))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
cursor->page_cur.rec= rec;
|
cursor->page_cur.rec= rec;
|
||||||
return btr_page_get_father_node_ptr(offsets, heap, cursor, mtr);
|
return btr_page_get_parent(offsets, heap, cursor, mtr);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Seek to the parent page of a B-tree page.
|
/** Seek to the parent page of a B-tree page.
|
||||||
@@ -811,7 +902,7 @@ bool btr_page_get_father(mtr_t* mtr, btr_cur_t* cursor)
|
|||||||
return false;
|
return false;
|
||||||
cursor->page_cur.rec= rec;
|
cursor->page_cur.rec= rec;
|
||||||
mem_heap_t *heap= mem_heap_create(100);
|
mem_heap_t *heap= mem_heap_create(100);
|
||||||
const bool got= btr_page_get_father_node_ptr(nullptr, heap, cursor, mtr);
|
const bool got= btr_page_get_parent(nullptr, heap, cursor, mtr);
|
||||||
mem_heap_free(heap);
|
mem_heap_free(heap);
|
||||||
return got;
|
return got;
|
||||||
}
|
}
|
||||||
@@ -1718,48 +1809,43 @@ void btr_set_instant(buf_block_t* root, const dict_index_t& index, mtr_t* mtr)
|
|||||||
/** Reset the table to the canonical format on ROLLBACK of instant ALTER TABLE.
|
/** Reset the table to the canonical format on ROLLBACK of instant ALTER TABLE.
|
||||||
@param[in] index clustered index with instant ALTER TABLE
|
@param[in] index clustered index with instant ALTER TABLE
|
||||||
@param[in] all whether to reset FIL_PAGE_TYPE as well
|
@param[in] all whether to reset FIL_PAGE_TYPE as well
|
||||||
@param[in,out] mtr mini-transaction
|
@param[in,out] mtr mini-transaction */
|
||||||
@return error code */
|
|
||||||
ATTRIBUTE_COLD
|
ATTRIBUTE_COLD
|
||||||
dberr_t btr_reset_instant(const dict_index_t &index, bool all, mtr_t *mtr)
|
void btr_reset_instant(const dict_index_t &index, bool all, mtr_t *mtr)
|
||||||
{
|
{
|
||||||
ut_ad(!index.table->is_temporary());
|
ut_ad(!index.table->is_temporary());
|
||||||
ut_ad(index.is_primary());
|
ut_ad(index.is_primary());
|
||||||
dberr_t err;
|
buf_block_t *root= btr_get_latched_root(index, mtr);
|
||||||
if (buf_block_t *root= btr_root_block_get(&index, RW_SX_LATCH, mtr, &err))
|
byte *page_type= root->page.frame + FIL_PAGE_TYPE;
|
||||||
|
if (all)
|
||||||
{
|
{
|
||||||
byte *page_type= root->page.frame + FIL_PAGE_TYPE;
|
ut_ad(mach_read_from_2(page_type) == FIL_PAGE_TYPE_INSTANT ||
|
||||||
if (all)
|
mach_read_from_2(page_type) == FIL_PAGE_INDEX);
|
||||||
{
|
mtr->write<2,mtr_t::MAYBE_NOP>(*root, page_type, FIL_PAGE_INDEX);
|
||||||
ut_ad(mach_read_from_2(page_type) == FIL_PAGE_TYPE_INSTANT ||
|
byte *instant= PAGE_INSTANT + PAGE_HEADER + root->page.frame;
|
||||||
mach_read_from_2(page_type) == FIL_PAGE_INDEX);
|
mtr->write<2,mtr_t::MAYBE_NOP>(*root, instant,
|
||||||
mtr->write<2,mtr_t::MAYBE_NOP>(*root, page_type, FIL_PAGE_INDEX);
|
page_ptr_get_direction(instant + 1));
|
||||||
byte *instant= PAGE_INSTANT + PAGE_HEADER + root->page.frame;
|
|
||||||
mtr->write<2,mtr_t::MAYBE_NOP>(*root, instant,
|
|
||||||
page_ptr_get_direction(instant + 1));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
ut_ad(mach_read_from_2(page_type) == FIL_PAGE_TYPE_INSTANT);
|
|
||||||
static const byte supremuminfimum[8 + 8] = "supremuminfimum";
|
|
||||||
uint16_t infimum, supremum;
|
|
||||||
if (page_is_comp(root->page.frame))
|
|
||||||
{
|
|
||||||
infimum= PAGE_NEW_INFIMUM;
|
|
||||||
supremum= PAGE_NEW_SUPREMUM;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
infimum= PAGE_OLD_INFIMUM;
|
|
||||||
supremum= PAGE_OLD_SUPREMUM;
|
|
||||||
}
|
|
||||||
ut_ad(!memcmp(&root->page.frame[infimum], supremuminfimum + 8, 8) ==
|
|
||||||
!memcmp(&root->page.frame[supremum], supremuminfimum, 8));
|
|
||||||
mtr->memcpy<mtr_t::MAYBE_NOP>(*root, &root->page.frame[infimum],
|
|
||||||
supremuminfimum + 8, 8);
|
|
||||||
mtr->memcpy<mtr_t::MAYBE_NOP>(*root, &root->page.frame[supremum],
|
|
||||||
supremuminfimum, 8);
|
|
||||||
}
|
}
|
||||||
return err;
|
else
|
||||||
|
ut_ad(mach_read_from_2(page_type) == FIL_PAGE_TYPE_INSTANT);
|
||||||
|
static const byte supremuminfimum[8 + 8] = "supremuminfimum";
|
||||||
|
uint16_t infimum, supremum;
|
||||||
|
if (page_is_comp(root->page.frame))
|
||||||
|
{
|
||||||
|
infimum= PAGE_NEW_INFIMUM;
|
||||||
|
supremum= PAGE_NEW_SUPREMUM;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
infimum= PAGE_OLD_INFIMUM;
|
||||||
|
supremum= PAGE_OLD_SUPREMUM;
|
||||||
|
}
|
||||||
|
ut_ad(!memcmp(&root->page.frame[infimum], supremuminfimum + 8, 8) ==
|
||||||
|
!memcmp(&root->page.frame[supremum], supremuminfimum, 8));
|
||||||
|
mtr->memcpy<mtr_t::MAYBE_NOP>(*root, &root->page.frame[infimum],
|
||||||
|
supremuminfimum + 8, 8);
|
||||||
|
mtr->memcpy<mtr_t::MAYBE_NOP>(*root, &root->page.frame[supremum],
|
||||||
|
supremuminfimum, 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*************************************************************//**
|
/*************************************************************//**
|
||||||
@@ -1856,11 +1942,6 @@ btr_root_raise_and_insert(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Copy the records from root to the new page one by one. */
|
/* Copy the records from root to the new page one by one. */
|
||||||
dberr_t e;
|
|
||||||
if (!err) {
|
|
||||||
err = &e;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (0
|
if (0
|
||||||
#ifdef UNIV_ZIP_COPY
|
#ifdef UNIV_ZIP_COPY
|
||||||
|| new_page_zip
|
|| new_page_zip
|
||||||
@@ -2004,21 +2085,15 @@ btr_root_raise_and_insert(
|
|||||||
page_cursor->block = new_block;
|
page_cursor->block = new_block;
|
||||||
page_cursor->index = index;
|
page_cursor->index = index;
|
||||||
|
|
||||||
if (tuple) {
|
ut_ad(dtuple_check_typed(tuple));
|
||||||
ut_ad(dtuple_check_typed(tuple));
|
/* Reposition the cursor to the child node */
|
||||||
/* Reposition the cursor to the child node */
|
ulint low_match = 0, up_match = 0;
|
||||||
ulint low_match = 0, up_match = 0;
|
|
||||||
|
|
||||||
if (page_cur_search_with_match(tuple, PAGE_CUR_LE,
|
if (page_cur_search_with_match(tuple, PAGE_CUR_LE,
|
||||||
&up_match, &low_match,
|
&up_match, &low_match,
|
||||||
page_cursor, nullptr)) {
|
page_cursor, nullptr)) {
|
||||||
if (err) {
|
*err = DB_CORRUPTION;
|
||||||
*err = DB_CORRUPTION;
|
return nullptr;
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
page_cursor->rec = page_get_infimum_rec(new_block->page.frame);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Split the child and insert tuple */
|
/* Split the child and insert tuple */
|
||||||
@@ -2237,6 +2312,7 @@ func_exit:
|
|||||||
return(rec);
|
return(rec);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef UNIV_DEBUG
|
||||||
/*************************************************************//**
|
/*************************************************************//**
|
||||||
Returns TRUE if the insert fits on the appropriate half-page with the
|
Returns TRUE if the insert fits on the appropriate half-page with the
|
||||||
chosen split_rec.
|
chosen split_rec.
|
||||||
@@ -2335,6 +2411,7 @@ got_rec:
|
|||||||
|
|
||||||
return(false);
|
return(false);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/*******************************************************//**
|
/*******************************************************//**
|
||||||
Inserts a data tuple to a tree on a non-leaf level. It is assumed
|
Inserts a data tuple to a tree on a non-leaf level. It is assumed
|
||||||
@@ -2357,25 +2434,34 @@ btr_insert_on_non_leaf_level(
|
|||||||
rtr_info_t rtr_info;
|
rtr_info_t rtr_info;
|
||||||
|
|
||||||
ut_ad(level > 0);
|
ut_ad(level > 0);
|
||||||
auto mode = PAGE_CUR_LE;
|
|
||||||
|
|
||||||
if (index->is_spatial()) {
|
|
||||||
mode = PAGE_CUR_RTREE_INSERT;
|
|
||||||
/* For spatial index, initialize structures to track
|
|
||||||
its parents etc. */
|
|
||||||
rtr_init_rtr_info(&rtr_info, false, &cursor, index, false);
|
|
||||||
|
|
||||||
rtr_info_update_btr(&cursor, &rtr_info);
|
|
||||||
}
|
|
||||||
|
|
||||||
flags |= BTR_NO_LOCKING_FLAG | BTR_KEEP_SYS_FLAG
|
flags |= BTR_NO_LOCKING_FLAG | BTR_KEEP_SYS_FLAG
|
||||||
| BTR_NO_UNDO_LOG_FLAG;
|
| BTR_NO_UNDO_LOG_FLAG;
|
||||||
cursor.page_cur.index = index;
|
cursor.page_cur.index = index;
|
||||||
|
|
||||||
dberr_t err = btr_cur_search_to_nth_level(level, tuple, mode,
|
dberr_t err;
|
||||||
BTR_CONT_MODIFY_TREE,
|
|
||||||
|
if (index->is_spatial()) {
|
||||||
|
/* For spatial index, initialize structures to track
|
||||||
|
its parents etc. */
|
||||||
|
rtr_init_rtr_info(&rtr_info, false, &cursor, index, false);
|
||||||
|
|
||||||
|
rtr_info_update_btr(&cursor, &rtr_info);
|
||||||
|
err = rtr_search_to_nth_level(level, tuple,
|
||||||
|
PAGE_CUR_RTREE_INSERT,
|
||||||
|
BTR_CONT_MODIFY_TREE,
|
||||||
|
&cursor, mtr);
|
||||||
|
} else {
|
||||||
|
err = btr_cur_search_to_nth_level(level, tuple, RW_X_LATCH,
|
||||||
&cursor, mtr);
|
&cursor, mtr);
|
||||||
|
}
|
||||||
|
|
||||||
ut_ad(cursor.flag == BTR_CUR_BINARY);
|
ut_ad(cursor.flag == BTR_CUR_BINARY);
|
||||||
|
#if 0 /* MDEV-29835 FIXME */
|
||||||
|
ut_ad(!btr_cur_get_block(&cursor)->page.lock.not_recursive()
|
||||||
|
|| index->is_spatial()
|
||||||
|
|| mtr->memo_contains(index->lock, MTR_MEMO_X_LOCK));
|
||||||
|
#endif
|
||||||
|
|
||||||
if (UNIV_LIKELY(err == DB_SUCCESS)) {
|
if (UNIV_LIKELY(err == DB_SUCCESS)) {
|
||||||
err = btr_cur_optimistic_insert(flags,
|
err = btr_cur_optimistic_insert(flags,
|
||||||
@@ -2471,6 +2557,7 @@ btr_attach_half_pages(
|
|||||||
/* Get the level of the split pages */
|
/* Get the level of the split pages */
|
||||||
const ulint level = btr_page_get_level(block->page.frame);
|
const ulint level = btr_page_get_level(block->page.frame);
|
||||||
ut_ad(level == btr_page_get_level(new_block->page.frame));
|
ut_ad(level == btr_page_get_level(new_block->page.frame));
|
||||||
|
page_id_t id{block->page.id()};
|
||||||
|
|
||||||
/* Get the previous and next pages of page */
|
/* Get the previous and next pages of page */
|
||||||
const uint32_t prev_page_no = btr_page_get_prev(block->page.frame);
|
const uint32_t prev_page_no = btr_page_get_prev(block->page.frame);
|
||||||
@@ -2478,12 +2565,32 @@ btr_attach_half_pages(
|
|||||||
|
|
||||||
/* for consistency, both blocks should be locked, before change */
|
/* for consistency, both blocks should be locked, before change */
|
||||||
if (prev_page_no != FIL_NULL && direction == FSP_DOWN) {
|
if (prev_page_no != FIL_NULL && direction == FSP_DOWN) {
|
||||||
prev_block = btr_block_get(*index, prev_page_no, RW_X_LATCH,
|
id.set_page_no(prev_page_no);
|
||||||
!level, mtr);
|
prev_block = mtr->get_already_latched(id, MTR_MEMO_PAGE_X_FIX);
|
||||||
|
#if 1 /* MDEV-29835 FIXME: acquire page latches upfront */
|
||||||
|
if (!prev_block) {
|
||||||
|
# if 0 /* MDEV-29835 FIXME */
|
||||||
|
ut_ad(mtr->memo_contains(index->lock,
|
||||||
|
MTR_MEMO_X_LOCK));
|
||||||
|
# endif
|
||||||
|
prev_block = btr_block_get(*index, prev_page_no,
|
||||||
|
RW_X_LATCH, !level, mtr);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
if (next_page_no != FIL_NULL && direction != FSP_DOWN) {
|
if (next_page_no != FIL_NULL && direction != FSP_DOWN) {
|
||||||
next_block = btr_block_get(*index, next_page_no, RW_X_LATCH,
|
id.set_page_no(next_page_no);
|
||||||
!level, mtr);
|
next_block = mtr->get_already_latched(id, MTR_MEMO_PAGE_X_FIX);
|
||||||
|
#if 1 /* MDEV-29835 FIXME: acquire page latches upfront */
|
||||||
|
if (!next_block) {
|
||||||
|
# if 0 /* MDEV-29835 FIXME */
|
||||||
|
ut_ad(mtr->memo_contains(index->lock,
|
||||||
|
MTR_MEMO_X_LOCK));
|
||||||
|
# endif
|
||||||
|
next_block = btr_block_get(*index, next_page_no,
|
||||||
|
RW_X_LATCH, !level, mtr);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Build the node pointer (= node key and page address) for the upper
|
/* Build the node pointer (= node key and page address) for the upper
|
||||||
@@ -3020,6 +3127,7 @@ insert_empty:
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef UNIV_DEBUG
|
||||||
/* If the split is made on the leaf level and the insert will fit
|
/* If the split is made on the leaf level and the insert will fit
|
||||||
on the appropriate half-page, we may release the tree x-latch.
|
on the appropriate half-page, we may release the tree x-latch.
|
||||||
We can then move the records after releasing the tree latch,
|
We can then move the records after releasing the tree latch,
|
||||||
@@ -3027,21 +3135,21 @@ insert_empty:
|
|||||||
const bool insert_will_fit = !new_page_zip
|
const bool insert_will_fit = !new_page_zip
|
||||||
&& btr_page_insert_fits(cursor, split_rec, offsets, tuple,
|
&& btr_page_insert_fits(cursor, split_rec, offsets, tuple,
|
||||||
n_ext, heap);
|
n_ext, heap);
|
||||||
|
#endif
|
||||||
if (!split_rec && !insert_left) {
|
if (!split_rec && !insert_left) {
|
||||||
UT_DELETE_ARRAY(buf);
|
UT_DELETE_ARRAY(buf);
|
||||||
buf = NULL;
|
buf = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!srv_read_only_mode
|
#if 0 // FIXME: this used to be a no-op, and may cause trouble if enabled
|
||||||
&& insert_will_fit
|
if (insert_will_fit
|
||||||
&& page_is_leaf(page)
|
&& page_is_leaf(page)
|
||||||
&& !dict_index_is_online_ddl(cursor->index())) {
|
&& !dict_index_is_online_ddl(cursor->index())) {
|
||||||
#if 0 // FIXME: this used to be a no-op, and may cause trouble if enabled
|
|
||||||
mtr->release(cursor->index()->lock);
|
mtr->release(cursor->index()->lock);
|
||||||
#endif
|
|
||||||
/* NOTE: We cannot release root block latch here, because it
|
/* NOTE: We cannot release root block latch here, because it
|
||||||
has segment header and already modified in most of cases.*/
|
has segment header and already modified in most of cases.*/
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* 5. Move then the records to the new page */
|
/* 5. Move then the records to the new page */
|
||||||
if (direction == FSP_DOWN) {
|
if (direction == FSP_DOWN) {
|
||||||
@@ -3273,52 +3381,58 @@ func_exit:
|
|||||||
dberr_t btr_level_list_remove(const buf_block_t& block,
|
dberr_t btr_level_list_remove(const buf_block_t& block,
|
||||||
const dict_index_t& index, mtr_t* mtr)
|
const dict_index_t& index, mtr_t* mtr)
|
||||||
{
|
{
|
||||||
ut_ad(mtr->memo_contains_flagged(&block, MTR_MEMO_PAGE_X_FIX));
|
ut_ad(mtr->memo_contains_flagged(&block, MTR_MEMO_PAGE_X_FIX));
|
||||||
ut_ad(block.zip_size() == index.table->space->zip_size());
|
ut_ad(block.zip_size() == index.table->space->zip_size());
|
||||||
ut_ad(index.table->space->id == block.page.id().space());
|
ut_ad(index.table->space->id == block.page.id().space());
|
||||||
/* Get the previous and next page numbers of page */
|
/* Get the previous and next page numbers of page */
|
||||||
|
const uint32_t prev_page_no= btr_page_get_prev(block.page.frame);
|
||||||
|
const uint32_t next_page_no= btr_page_get_next(block.page.frame);
|
||||||
|
page_id_t id{block.page.id()};
|
||||||
|
buf_block_t *prev= nullptr, *next;
|
||||||
|
dberr_t err;
|
||||||
|
|
||||||
const page_t* page = block.page.frame;
|
/* Update page links of the level */
|
||||||
const uint32_t prev_page_no = btr_page_get_prev(page);
|
if (prev_page_no != FIL_NULL)
|
||||||
const uint32_t next_page_no = btr_page_get_next(page);
|
{
|
||||||
|
id.set_page_no(prev_page_no);
|
||||||
|
prev= mtr->get_already_latched(id, MTR_MEMO_PAGE_X_FIX);
|
||||||
|
#if 1 /* MDEV-29835 FIXME: acquire page latches upfront */
|
||||||
|
if (!prev)
|
||||||
|
{
|
||||||
|
# if 0 /* MDEV-29835 FIXME */
|
||||||
|
ut_ad(mtr->memo_contains(index.lock, MTR_MEMO_X_LOCK));
|
||||||
|
# endif
|
||||||
|
prev= btr_block_get(index, id.page_no(), RW_X_LATCH,
|
||||||
|
page_is_leaf(block.page.frame), mtr, &err);
|
||||||
|
if (UNIV_UNLIKELY(!prev))
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
/* Update page links of the level */
|
if (next_page_no != FIL_NULL)
|
||||||
dberr_t err;
|
{
|
||||||
|
id.set_page_no(next_page_no);
|
||||||
|
next= mtr->get_already_latched(id, MTR_MEMO_PAGE_X_FIX);
|
||||||
|
#if 1 /* MDEV-29835 FIXME: acquire page latches upfront */
|
||||||
|
if (!next)
|
||||||
|
{
|
||||||
|
# if 0 /* MDEV-29835 FIXME */
|
||||||
|
ut_ad(mtr->memo_contains(index.lock, MTR_MEMO_X_LOCK));
|
||||||
|
# endif
|
||||||
|
next= btr_block_get(index, id.page_no(), RW_X_LATCH,
|
||||||
|
page_is_leaf(block.page.frame), mtr, &err);
|
||||||
|
if (UNIV_UNLIKELY(!next))
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
btr_page_set_prev(next, prev_page_no, mtr);
|
||||||
|
}
|
||||||
|
|
||||||
if (prev_page_no != FIL_NULL) {
|
if (prev)
|
||||||
buf_block_t* prev_block = btr_block_get(
|
btr_page_set_next(prev, next_page_no, mtr);
|
||||||
index, prev_page_no, RW_X_LATCH, page_is_leaf(page),
|
|
||||||
mtr, &err);
|
|
||||||
if (UNIV_UNLIKELY(!prev_block)) {
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
if (UNIV_UNLIKELY(memcmp_aligned<4>(prev_block->page.frame
|
|
||||||
+ FIL_PAGE_NEXT,
|
|
||||||
page + FIL_PAGE_OFFSET,
|
|
||||||
4))) {
|
|
||||||
return DB_CORRUPTION;
|
|
||||||
}
|
|
||||||
btr_page_set_next(prev_block, next_page_no, mtr);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (next_page_no != FIL_NULL) {
|
return DB_SUCCESS;
|
||||||
buf_block_t* next_block = btr_block_get(
|
|
||||||
index, next_page_no, RW_X_LATCH, page_is_leaf(page),
|
|
||||||
mtr, &err);
|
|
||||||
|
|
||||||
if (UNIV_UNLIKELY(!next_block)) {
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
if (UNIV_UNLIKELY(memcmp_aligned<4>(next_block->page.frame
|
|
||||||
+ FIL_PAGE_PREV,
|
|
||||||
page + FIL_PAGE_OFFSET,
|
|
||||||
4))) {
|
|
||||||
return DB_CORRUPTION;
|
|
||||||
}
|
|
||||||
btr_page_set_prev(next_block, prev_page_no, mtr);
|
|
||||||
}
|
|
||||||
|
|
||||||
return DB_SUCCESS;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*************************************************************//**
|
/*************************************************************//**
|
||||||
@@ -4168,23 +4282,30 @@ btr_discard_page(
|
|||||||
|
|
||||||
const uint32_t left_page_no = btr_page_get_prev(block->page.frame);
|
const uint32_t left_page_no = btr_page_get_prev(block->page.frame);
|
||||||
const uint32_t right_page_no = btr_page_get_next(block->page.frame);
|
const uint32_t right_page_no = btr_page_get_next(block->page.frame);
|
||||||
|
page_id_t merge_page_id{block->page.id()};
|
||||||
|
|
||||||
ut_d(bool parent_is_different = false);
|
ut_d(bool parent_is_different = false);
|
||||||
|
dberr_t err;
|
||||||
if (left_page_no != FIL_NULL) {
|
if (left_page_no != FIL_NULL) {
|
||||||
dberr_t err;
|
merge_page_id.set_page_no(left_page_no);
|
||||||
merge_block = btr_block_get(*index, left_page_no, RW_X_LATCH,
|
merge_block = btr_block_reget(mtr, *index, merge_page_id,
|
||||||
true, mtr, &err);
|
RW_X_LATCH, &err);
|
||||||
if (UNIV_UNLIKELY(!merge_block)) {
|
if (UNIV_UNLIKELY(!merge_block)) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
#if 0 /* MDEV-29385 FIXME: Acquire the page latch upfront. */
|
||||||
|
ut_ad(!memcmp_aligned<4>(merge_block->page.frame
|
||||||
|
+ FIL_PAGE_NEXT,
|
||||||
|
block->page.frame + FIL_PAGE_OFFSET,
|
||||||
|
4));
|
||||||
|
#else
|
||||||
if (UNIV_UNLIKELY(memcmp_aligned<4>(merge_block->page.frame
|
if (UNIV_UNLIKELY(memcmp_aligned<4>(merge_block->page.frame
|
||||||
+ FIL_PAGE_NEXT,
|
+ FIL_PAGE_NEXT,
|
||||||
block->page.frame
|
block->page.frame
|
||||||
+ FIL_PAGE_OFFSET, 4))) {
|
+ FIL_PAGE_OFFSET, 4))) {
|
||||||
return DB_CORRUPTION;
|
return DB_CORRUPTION;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
ut_d(parent_is_different =
|
ut_d(parent_is_different =
|
||||||
(page_rec_get_next(
|
(page_rec_get_next(
|
||||||
page_get_infimum_rec(
|
page_get_infimum_rec(
|
||||||
@@ -4192,19 +4313,25 @@ btr_discard_page(
|
|||||||
&parent_cursor)))
|
&parent_cursor)))
|
||||||
== btr_cur_get_rec(&parent_cursor)));
|
== btr_cur_get_rec(&parent_cursor)));
|
||||||
} else if (right_page_no != FIL_NULL) {
|
} else if (right_page_no != FIL_NULL) {
|
||||||
dberr_t err;
|
merge_page_id.set_page_no(right_page_no);
|
||||||
merge_block = btr_block_get(*index, right_page_no, RW_X_LATCH,
|
merge_block = btr_block_reget(mtr, *index, merge_page_id,
|
||||||
true, mtr, &err);
|
RW_X_LATCH, &err);
|
||||||
if (UNIV_UNLIKELY(!merge_block)) {
|
if (UNIV_UNLIKELY(!merge_block)) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
#if 0 /* MDEV-29385 FIXME: Acquire the page latch upfront. */
|
||||||
|
ut_ad(!memcmp_aligned<4>(merge_block->page.frame
|
||||||
|
+ FIL_PAGE_PREV,
|
||||||
|
block->page.frame + FIL_PAGE_OFFSET,
|
||||||
|
4));
|
||||||
|
#else
|
||||||
if (UNIV_UNLIKELY(memcmp_aligned<4>(merge_block->page.frame
|
if (UNIV_UNLIKELY(memcmp_aligned<4>(merge_block->page.frame
|
||||||
+ FIL_PAGE_PREV,
|
+ FIL_PAGE_PREV,
|
||||||
block->page.frame
|
block->page.frame
|
||||||
+ FIL_PAGE_OFFSET, 4))) {
|
+ FIL_PAGE_OFFSET, 4))) {
|
||||||
return DB_CORRUPTION;
|
return DB_CORRUPTION;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
ut_d(parent_is_different = page_rec_is_supremum(
|
ut_d(parent_is_different = page_rec_is_supremum(
|
||||||
page_rec_get_next(btr_cur_get_rec(&parent_cursor))));
|
page_rec_get_next(btr_cur_get_rec(&parent_cursor))));
|
||||||
if (page_is_leaf(merge_block->page.frame)) {
|
if (page_is_leaf(merge_block->page.frame)) {
|
||||||
@@ -4246,13 +4373,10 @@ btr_discard_page(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef UNIV_ZIP_DEBUG
|
#ifdef UNIV_ZIP_DEBUG
|
||||||
{
|
if (page_zip_des_t* merge_page_zip
|
||||||
page_zip_des_t* merge_page_zip
|
= buf_block_get_page_zip(merge_block));
|
||||||
= buf_block_get_page_zip(merge_block);
|
ut_a(page_zip_validate(merge_page_zip,
|
||||||
ut_a(!merge_page_zip
|
merge_block->page.frame, index));
|
||||||
|| page_zip_validate(merge_page_zip,
|
|
||||||
merge_block->page.frame, index));
|
|
||||||
}
|
|
||||||
#endif /* UNIV_ZIP_DEBUG */
|
#endif /* UNIV_ZIP_DEBUG */
|
||||||
|
|
||||||
if (index->has_locking()) {
|
if (index->has_locking()) {
|
||||||
@@ -4271,7 +4395,7 @@ btr_discard_page(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Free the file page */
|
/* Free the file page */
|
||||||
dberr_t err = btr_page_free(index, block, mtr);
|
err = btr_page_free(index, block, mtr);
|
||||||
|
|
||||||
if (err == DB_SUCCESS) {
|
if (err == DB_SUCCESS) {
|
||||||
/* btr_check_node_ptr() needs parent block latched.
|
/* btr_check_node_ptr() needs parent block latched.
|
||||||
@@ -4464,6 +4588,8 @@ btr_check_node_ptr(
|
|||||||
offsets = btr_page_get_father_block(NULL, heap, mtr, &cursor);
|
offsets = btr_page_get_father_block(NULL, heap, mtr, &cursor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ut_ad(offsets);
|
||||||
|
|
||||||
if (page_is_leaf(page)) {
|
if (page_is_leaf(page)) {
|
||||||
|
|
||||||
goto func_exit;
|
goto func_exit;
|
||||||
@@ -4796,19 +4922,16 @@ btr_validate_level(
|
|||||||
page_zip_des_t* page_zip;
|
page_zip_des_t* page_zip;
|
||||||
#endif /* UNIV_ZIP_DEBUG */
|
#endif /* UNIV_ZIP_DEBUG */
|
||||||
ulint savepoint = 0;
|
ulint savepoint = 0;
|
||||||
ulint savepoint2 = 0;
|
|
||||||
uint32_t parent_page_no = FIL_NULL;
|
uint32_t parent_page_no = FIL_NULL;
|
||||||
uint32_t parent_right_page_no = FIL_NULL;
|
uint32_t parent_right_page_no = FIL_NULL;
|
||||||
bool rightmost_child = false;
|
bool rightmost_child = false;
|
||||||
|
|
||||||
mtr.start();
|
mtr.start();
|
||||||
|
|
||||||
if (!srv_read_only_mode) {
|
if (lockout) {
|
||||||
if (lockout) {
|
mtr_x_lock_index(index, &mtr);
|
||||||
mtr_x_lock_index(index, &mtr);
|
} else {
|
||||||
} else {
|
mtr_sx_lock_index(index, &mtr);
|
||||||
mtr_sx_lock_index(index, &mtr);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dberr_t err;
|
dberr_t err;
|
||||||
@@ -4856,7 +4979,6 @@ corrupted:
|
|||||||
offsets = rec_get_offsets(node_ptr, index, offsets, 0,
|
offsets = rec_get_offsets(node_ptr, index, offsets, 0,
|
||||||
ULINT_UNDEFINED, &heap);
|
ULINT_UNDEFINED, &heap);
|
||||||
|
|
||||||
savepoint2 = mtr_set_savepoint(&mtr);
|
|
||||||
block = btr_node_ptr_get_child(node_ptr, index, offsets, &mtr,
|
block = btr_node_ptr_get_child(node_ptr, index, offsets, &mtr,
|
||||||
&err);
|
&err);
|
||||||
if (!block) {
|
if (!block) {
|
||||||
@@ -4877,10 +4999,8 @@ corrupted:
|
|||||||
/* To obey latch order of tree blocks,
|
/* To obey latch order of tree blocks,
|
||||||
we should release the right_block once to
|
we should release the right_block once to
|
||||||
obtain lock of the uncle block. */
|
obtain lock of the uncle block. */
|
||||||
mtr_release_block_at_savepoint(
|
mtr.release_last_page();
|
||||||
&mtr, savepoint2, block);
|
|
||||||
|
|
||||||
savepoint2 = mtr_set_savepoint(&mtr);
|
|
||||||
block = btr_block_get(*index, left_page_no,
|
block = btr_block_get(*index, left_page_no,
|
||||||
RW_SX_LATCH, false,
|
RW_SX_LATCH, false,
|
||||||
&mtr, &err);
|
&mtr, &err);
|
||||||
@@ -4908,12 +5028,10 @@ func_exit:
|
|||||||
mem_heap_empty(heap);
|
mem_heap_empty(heap);
|
||||||
offsets = offsets2 = NULL;
|
offsets = offsets2 = NULL;
|
||||||
|
|
||||||
if (!srv_read_only_mode) {
|
if (lockout) {
|
||||||
if (lockout) {
|
mtr_x_lock_index(index, &mtr);
|
||||||
mtr_x_lock_index(index, &mtr);
|
} else {
|
||||||
} else {
|
mtr_sx_lock_index(index, &mtr);
|
||||||
mtr_sx_lock_index(index, &mtr);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
page = block->page.frame;
|
page = block->page.frame;
|
||||||
@@ -4958,7 +5076,7 @@ func_exit:
|
|||||||
|
|
||||||
if (right_page_no != FIL_NULL) {
|
if (right_page_no != FIL_NULL) {
|
||||||
const rec_t* right_rec;
|
const rec_t* right_rec;
|
||||||
savepoint = mtr_set_savepoint(&mtr);
|
savepoint = mtr.get_savepoint();
|
||||||
|
|
||||||
right_block = btr_block_get(*index, right_page_no, RW_SX_LATCH,
|
right_block = btr_block_get(*index, right_page_no, RW_SX_LATCH,
|
||||||
!level, &mtr, &err);
|
!level, &mtr, &err);
|
||||||
@@ -5152,8 +5270,10 @@ broken_links:
|
|||||||
/* To obey latch order of tree blocks,
|
/* To obey latch order of tree blocks,
|
||||||
we should release the right_block once to
|
we should release the right_block once to
|
||||||
obtain lock of the uncle block. */
|
obtain lock of the uncle block. */
|
||||||
mtr_release_block_at_savepoint(
|
ut_ad(right_block
|
||||||
&mtr, savepoint, right_block);
|
== mtr.at_savepoint(savepoint));
|
||||||
|
mtr.rollback_to_savepoint(savepoint,
|
||||||
|
savepoint + 1);
|
||||||
|
|
||||||
if (parent_right_page_no != FIL_NULL) {
|
if (parent_right_page_no != FIL_NULL) {
|
||||||
btr_block_get(*index,
|
btr_block_get(*index,
|
||||||
|
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,7 @@
|
|||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
|
|
||||||
Copyright (C) 2012, 2014 Facebook, Inc. All Rights Reserved.
|
Copyright (C) 2012, 2014 Facebook, Inc. All Rights Reserved.
|
||||||
Copyright (C) 2014, 2022, MariaDB Corporation.
|
Copyright (C) 2014, 2023, MariaDB Corporation.
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify it under
|
This program is free software; you can redistribute it and/or modify it under
|
||||||
the terms of the GNU General Public License as published by the Free Software
|
the terms of the GNU General Public License as published by the Free Software
|
||||||
@@ -280,6 +280,70 @@ btr_defragment_calc_n_recs_for_size(
|
|||||||
return n_recs;
|
return n_recs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MY_ATTRIBUTE((nonnull(2,3,4), warn_unused_result))
|
||||||
|
/************************************************************//**
|
||||||
|
Returns the upper level node pointer to a page. It is assumed that mtr holds
|
||||||
|
an sx-latch on the tree.
|
||||||
|
@return rec_get_offsets() of the node pointer record */
|
||||||
|
static
|
||||||
|
rec_offs*
|
||||||
|
btr_page_search_father_node_ptr(
|
||||||
|
rec_offs* offsets,/*!< in: work area for the return value */
|
||||||
|
mem_heap_t* heap, /*!< in: memory heap to use */
|
||||||
|
btr_cur_t* cursor, /*!< in: cursor pointing to user record,
|
||||||
|
out: cursor on node pointer record,
|
||||||
|
its page x-latched */
|
||||||
|
mtr_t* mtr) /*!< in: mtr */
|
||||||
|
{
|
||||||
|
const uint32_t page_no = btr_cur_get_block(cursor)->page.id().page_no();
|
||||||
|
dict_index_t* index = btr_cur_get_index(cursor);
|
||||||
|
ut_ad(!index->is_spatial());
|
||||||
|
|
||||||
|
ut_ad(mtr->memo_contains_flagged(&index->lock, MTR_MEMO_X_LOCK
|
||||||
|
| MTR_MEMO_SX_LOCK));
|
||||||
|
ut_ad(dict_index_get_page(index) != page_no);
|
||||||
|
|
||||||
|
const auto level = btr_page_get_level(btr_cur_get_page(cursor));
|
||||||
|
|
||||||
|
const rec_t* user_rec = btr_cur_get_rec(cursor);
|
||||||
|
ut_a(page_rec_is_user_rec(user_rec));
|
||||||
|
|
||||||
|
if (btr_cur_search_to_nth_level(level + 1,
|
||||||
|
dict_index_build_node_ptr(index,
|
||||||
|
user_rec, 0,
|
||||||
|
heap, level),
|
||||||
|
RW_X_LATCH,
|
||||||
|
cursor, mtr) != DB_SUCCESS) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
const rec_t* node_ptr = btr_cur_get_rec(cursor);
|
||||||
|
ut_ad(!btr_cur_get_block(cursor)->page.lock.not_recursive()
|
||||||
|
|| mtr->memo_contains(index->lock, MTR_MEMO_X_LOCK));
|
||||||
|
|
||||||
|
offsets = rec_get_offsets(node_ptr, index, offsets, 0,
|
||||||
|
ULINT_UNDEFINED, &heap);
|
||||||
|
|
||||||
|
if (btr_node_ptr_get_child_page_no(node_ptr, offsets) != page_no) {
|
||||||
|
offsets = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return(offsets);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool btr_page_search_father(mtr_t *mtr, btr_cur_t *cursor)
|
||||||
|
{
|
||||||
|
rec_t *rec=
|
||||||
|
page_rec_get_next(page_get_infimum_rec(cursor->block()->page.frame));
|
||||||
|
if (UNIV_UNLIKELY(!rec))
|
||||||
|
return false;
|
||||||
|
cursor->page_cur.rec= rec;
|
||||||
|
mem_heap_t *heap= mem_heap_create(100);
|
||||||
|
const bool got= btr_page_search_father_node_ptr(nullptr, heap, cursor, mtr);
|
||||||
|
mem_heap_free(heap);
|
||||||
|
return got;
|
||||||
|
}
|
||||||
|
|
||||||
/*************************************************************//**
|
/*************************************************************//**
|
||||||
Merge as many records from the from_block to the to_block. Delete
|
Merge as many records from the from_block to the to_block. Delete
|
||||||
the from_block if all records are successfully merged to to_block.
|
the from_block if all records are successfully merged to to_block.
|
||||||
@@ -408,7 +472,7 @@ btr_defragment_merge_pages(
|
|||||||
parent.page_cur.index = index;
|
parent.page_cur.index = index;
|
||||||
parent.page_cur.block = from_block;
|
parent.page_cur.block = from_block;
|
||||||
|
|
||||||
if (!btr_page_get_father(mtr, &parent)) {
|
if (!btr_page_search_father(mtr, &parent)) {
|
||||||
to_block = nullptr;
|
to_block = nullptr;
|
||||||
} else if (n_recs_to_move == n_recs) {
|
} else if (n_recs_to_move == n_recs) {
|
||||||
/* The whole page is merged with the previous page,
|
/* The whole page is merged with the previous page,
|
||||||
@@ -699,10 +763,9 @@ processed:
|
|||||||
acquire index->lock X-latch. This entitles us to
|
acquire index->lock X-latch. This entitles us to
|
||||||
acquire page latches in any order for the index. */
|
acquire page latches in any order for the index. */
|
||||||
mtr_x_lock_index(index, &mtr);
|
mtr_x_lock_index(index, &mtr);
|
||||||
/* This will acquire index->lock U latch, which is allowed
|
|
||||||
when we are already holding the X-latch. */
|
|
||||||
if (buf_block_t *last_block =
|
if (buf_block_t *last_block =
|
||||||
item->pcur->restore_position(BTR_MODIFY_TREE, &mtr)
|
item->pcur->restore_position(
|
||||||
|
BTR_PURGE_TREE_ALREADY_LATCHED, &mtr)
|
||||||
== btr_pcur_t::CORRUPTED
|
== btr_pcur_t::CORRUPTED
|
||||||
? nullptr
|
? nullptr
|
||||||
: btr_defragment_n_pages(btr_pcur_get_block(item->pcur),
|
: btr_defragment_n_pages(btr_pcur_get_block(item->pcur),
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
|
|
||||||
Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
|
Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
|
||||||
Copyright (c) 2016, 2022, MariaDB Corporation.
|
Copyright (c) 2016, 2023, MariaDB Corporation.
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify it under
|
This program is free software; you can redistribute it and/or modify it under
|
||||||
the terms of the GNU General Public License as published by the Free Software
|
the terms of the GNU General Public License as published by the Free Software
|
||||||
@@ -212,24 +212,98 @@ btr_pcur_copy_stored_position(
|
|||||||
pcur_receive->old_n_fields = pcur_donate->old_n_fields;
|
pcur_receive->old_n_fields = pcur_donate->old_n_fields;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Optimistically latches the leaf page or pages requested.
|
||||||
|
@param[in] block guessed buffer block
|
||||||
|
@param[in,out] pcur cursor
|
||||||
|
@param[in,out] latch_mode BTR_SEARCH_LEAF, ...
|
||||||
|
@param[in,out] mtr mini-transaction
|
||||||
|
@return true if success */
|
||||||
|
TRANSACTIONAL_TARGET
|
||||||
|
static bool btr_pcur_optimistic_latch_leaves(buf_block_t *block,
|
||||||
|
btr_pcur_t *pcur,
|
||||||
|
btr_latch_mode *latch_mode,
|
||||||
|
mtr_t *mtr)
|
||||||
|
{
|
||||||
|
ut_ad(block->page.buf_fix_count());
|
||||||
|
ut_ad(block->page.in_file());
|
||||||
|
ut_ad(block->page.frame);
|
||||||
|
|
||||||
|
static_assert(BTR_SEARCH_PREV & BTR_SEARCH_LEAF, "");
|
||||||
|
static_assert(BTR_MODIFY_PREV & BTR_MODIFY_LEAF, "");
|
||||||
|
static_assert((BTR_SEARCH_PREV ^ BTR_MODIFY_PREV) ==
|
||||||
|
(RW_S_LATCH ^ RW_X_LATCH), "");
|
||||||
|
|
||||||
|
const rw_lock_type_t mode=
|
||||||
|
rw_lock_type_t(*latch_mode & (RW_X_LATCH | RW_S_LATCH));
|
||||||
|
|
||||||
|
switch (*latch_mode) {
|
||||||
|
default:
|
||||||
|
ut_ad(*latch_mode == BTR_SEARCH_LEAF || *latch_mode == BTR_MODIFY_LEAF);
|
||||||
|
return buf_page_optimistic_get(mode, block, pcur->modify_clock, mtr);
|
||||||
|
case BTR_SEARCH_PREV:
|
||||||
|
case BTR_MODIFY_PREV:
|
||||||
|
page_id_t id{0};
|
||||||
|
uint32_t left_page_no;
|
||||||
|
ulint zip_size;
|
||||||
|
buf_block_t *left_block= nullptr;
|
||||||
|
{
|
||||||
|
transactional_shared_lock_guard<block_lock> g{block->page.lock};
|
||||||
|
if (block->modify_clock != pcur->modify_clock)
|
||||||
|
return false;
|
||||||
|
id= block->page.id();
|
||||||
|
zip_size= block->zip_size();
|
||||||
|
left_page_no= btr_page_get_prev(block->page.frame);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (left_page_no != FIL_NULL)
|
||||||
|
{
|
||||||
|
left_block=
|
||||||
|
buf_page_get_gen(page_id_t(id.space(), left_page_no), zip_size,
|
||||||
|
mode, nullptr, BUF_GET_POSSIBLY_FREED, mtr);
|
||||||
|
|
||||||
|
if (left_block &&
|
||||||
|
btr_page_get_next(left_block->page.frame) != id.page_no())
|
||||||
|
{
|
||||||
|
release_left_block:
|
||||||
|
mtr->release_last_page();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buf_page_optimistic_get(mode, block, pcur->modify_clock, mtr))
|
||||||
|
{
|
||||||
|
if (btr_page_get_prev(block->page.frame) == left_page_no)
|
||||||
|
{
|
||||||
|
/* block was already buffer-fixed while entering the function and
|
||||||
|
buf_page_optimistic_get() buffer-fixes it again. */
|
||||||
|
ut_ad(2 <= block->page.buf_fix_count());
|
||||||
|
*latch_mode= btr_latch_mode(mode);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
mtr->release_last_page();
|
||||||
|
}
|
||||||
|
|
||||||
|
ut_ad(block->page.buf_fix_count());
|
||||||
|
if (left_block)
|
||||||
|
goto release_left_block;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Structure acts as functor to do the latching of leaf pages.
|
/** Structure acts as functor to do the latching of leaf pages.
|
||||||
It returns true if latching of leaf pages succeeded and false
|
It returns true if latching of leaf pages succeeded and false
|
||||||
otherwise. */
|
otherwise. */
|
||||||
struct optimistic_latch_leaves
|
struct optimistic_latch_leaves
|
||||||
{
|
{
|
||||||
btr_pcur_t *const cursor;
|
btr_pcur_t *const cursor;
|
||||||
btr_latch_mode *latch_mode;
|
btr_latch_mode *const latch_mode;
|
||||||
mtr_t *const mtr;
|
mtr_t *const mtr;
|
||||||
|
|
||||||
optimistic_latch_leaves(btr_pcur_t *cursor, btr_latch_mode *latch_mode,
|
bool operator()(buf_block_t *hint) const
|
||||||
mtr_t *mtr)
|
|
||||||
: cursor(cursor), latch_mode(latch_mode), mtr(mtr) {}
|
|
||||||
|
|
||||||
bool operator() (buf_block_t *hint) const
|
|
||||||
{
|
{
|
||||||
return hint && btr_cur_optimistic_latch_leaves(
|
return hint &&
|
||||||
hint, cursor->modify_clock, latch_mode,
|
btr_pcur_optimistic_latch_leaves(hint, cursor, latch_mode, mtr);
|
||||||
btr_pcur_get_btr_cur(cursor), mtr);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -246,8 +320,8 @@ record GREATER than the user record which was the predecessor of the
|
|||||||
supremum.
|
supremum.
|
||||||
(4) cursor was positioned before the first or after the last in an
|
(4) cursor was positioned before the first or after the last in an
|
||||||
empty tree: restores to before first or after the last in the tree.
|
empty tree: restores to before first or after the last in the tree.
|
||||||
@param restore_latch_mode BTR_SEARCH_LEAF, ...
|
@param latch_mode BTR_SEARCH_LEAF, ...
|
||||||
@param mtr mtr
|
@param mtr mini-transaction
|
||||||
@return btr_pcur_t::SAME_ALL cursor position on user rec and points on
|
@return btr_pcur_t::SAME_ALL cursor position on user rec and points on
|
||||||
the record with the same field values as in the stored record,
|
the record with the same field values as in the stored record,
|
||||||
btr_pcur_t::SAME_UNIQ cursor position is on user rec and points on the
|
btr_pcur_t::SAME_UNIQ cursor position is on user rec and points on the
|
||||||
@@ -301,10 +375,9 @@ btr_pcur_t::restore_position(btr_latch_mode restore_latch_mode, mtr_t *mtr)
|
|||||||
case BTR_SEARCH_PREV:
|
case BTR_SEARCH_PREV:
|
||||||
case BTR_MODIFY_PREV:
|
case BTR_MODIFY_PREV:
|
||||||
/* Try optimistic restoration. */
|
/* Try optimistic restoration. */
|
||||||
|
|
||||||
if (block_when_stored.run_with_hint(
|
if (block_when_stored.run_with_hint(
|
||||||
optimistic_latch_leaves(this, &restore_latch_mode,
|
optimistic_latch_leaves{this, &restore_latch_mode,
|
||||||
mtr))) {
|
mtr})) {
|
||||||
pos_state = BTR_PCUR_IS_POSITIONED;
|
pos_state = BTR_PCUR_IS_POSITIONED;
|
||||||
latch_mode = restore_latch_mode;
|
latch_mode = restore_latch_mode;
|
||||||
|
|
||||||
@@ -465,18 +538,9 @@ btr_pcur_move_to_next_page(
|
|||||||
return DB_CORRUPTION;
|
return DB_CORRUPTION;
|
||||||
}
|
}
|
||||||
|
|
||||||
ulint mode = cursor->latch_mode;
|
|
||||||
switch (mode) {
|
|
||||||
case BTR_SEARCH_TREE:
|
|
||||||
mode = BTR_SEARCH_LEAF;
|
|
||||||
break;
|
|
||||||
case BTR_MODIFY_TREE:
|
|
||||||
mode = BTR_MODIFY_LEAF;
|
|
||||||
}
|
|
||||||
|
|
||||||
dberr_t err;
|
dberr_t err;
|
||||||
buf_block_t* next_block = btr_block_get(
|
buf_block_t* next_block = btr_block_get(
|
||||||
*cursor->index(), next_page_no, mode,
|
*cursor->index(), next_page_no, cursor->latch_mode & ~12,
|
||||||
page_is_leaf(page), mtr, &err);
|
page_is_leaf(page), mtr, &err);
|
||||||
|
|
||||||
if (UNIV_UNLIKELY(!next_block)) {
|
if (UNIV_UNLIKELY(!next_block)) {
|
||||||
@@ -538,26 +602,42 @@ btr_pcur_move_backward_from_page(
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
buf_block_t* release_block = nullptr;
|
buf_block_t* block = btr_pcur_get_block(cursor);
|
||||||
|
|
||||||
if (!page_has_prev(btr_pcur_get_page(cursor))) {
|
if (page_has_prev(block->page.frame)) {
|
||||||
} else if (btr_pcur_is_before_first_on_page(cursor)) {
|
buf_block_t* left_block
|
||||||
release_block = btr_pcur_get_block(cursor);
|
= mtr->at_savepoint(mtr->get_savepoint() - 1);
|
||||||
page_cur_set_after_last(cursor->btr_cur.left_block,
|
const page_t* const left = left_block->page.frame;
|
||||||
btr_pcur_get_page_cur(cursor));
|
if (memcmp_aligned<4>(left + FIL_PAGE_NEXT,
|
||||||
} else {
|
block->page.frame
|
||||||
/* The repositioned cursor did not end on an infimum
|
+ FIL_PAGE_OFFSET, 4)) {
|
||||||
record on a page. Cursor repositioning acquired a latch
|
/* This should be the right sibling page, or
|
||||||
also on the previous page, but we do not need the latch:
|
if there is none, the current block. */
|
||||||
release it. */
|
ut_ad(left_block == block
|
||||||
release_block = cursor->btr_cur.left_block;
|
|| !memcmp_aligned<4>(left + FIL_PAGE_PREV,
|
||||||
|
block->page.frame
|
||||||
|
+ FIL_PAGE_OFFSET, 4));
|
||||||
|
/* The previous one must be the left sibling. */
|
||||||
|
left_block
|
||||||
|
= mtr->at_savepoint(mtr->get_savepoint() - 2);
|
||||||
|
ut_ad(!memcmp_aligned<4>(left_block->page.frame
|
||||||
|
+ FIL_PAGE_NEXT,
|
||||||
|
block->page.frame
|
||||||
|
+ FIL_PAGE_OFFSET, 4));
|
||||||
|
}
|
||||||
|
if (btr_pcur_is_before_first_on_page(cursor)) {
|
||||||
|
page_cur_set_after_last(left_block,
|
||||||
|
&cursor->btr_cur.page_cur);
|
||||||
|
/* Release the right sibling. */
|
||||||
|
} else {
|
||||||
|
/* Release the left sibling. */
|
||||||
|
block = left_block;
|
||||||
|
}
|
||||||
|
mtr->release(*block);
|
||||||
}
|
}
|
||||||
|
|
||||||
cursor->latch_mode = latch_mode;
|
cursor->latch_mode = latch_mode;
|
||||||
cursor->old_rec = nullptr;
|
cursor->old_rec = nullptr;
|
||||||
if (release_block) {
|
|
||||||
mtr->release(*release_block);
|
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1057,26 +1057,24 @@ btr_search_guess_on_hash(
|
|||||||
index_id_t index_id;
|
index_id_t index_id;
|
||||||
|
|
||||||
ut_ad(mtr->is_active());
|
ut_ad(mtr->is_active());
|
||||||
|
ut_ad(index->is_btree() || index->is_ibuf());
|
||||||
if (!btr_search_enabled) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
ut_ad(!index->is_ibuf());
|
|
||||||
ut_ad(latch_mode == BTR_SEARCH_LEAF || latch_mode == BTR_MODIFY_LEAF);
|
|
||||||
compile_time_assert(ulint{BTR_SEARCH_LEAF} == ulint{RW_S_LATCH});
|
|
||||||
compile_time_assert(ulint{BTR_MODIFY_LEAF} == ulint{RW_X_LATCH});
|
|
||||||
|
|
||||||
/* Not supported for spatial index */
|
|
||||||
ut_ad(!dict_index_is_spatial(index));
|
|
||||||
|
|
||||||
/* Note that, for efficiency, the struct info may not be protected by
|
/* Note that, for efficiency, the struct info may not be protected by
|
||||||
any latch here! */
|
any latch here! */
|
||||||
|
|
||||||
if (info->n_hash_potential == 0) {
|
if (latch_mode > BTR_MODIFY_LEAF
|
||||||
|
|| !info->last_hash_succ || !info->n_hash_potential
|
||||||
|
|| (tuple->info_bits & REC_INFO_MIN_REC_FLAG)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ut_ad(index->is_btree());
|
||||||
|
ut_ad(!index->table->is_temporary());
|
||||||
|
|
||||||
|
ut_ad(latch_mode == BTR_SEARCH_LEAF || latch_mode == BTR_MODIFY_LEAF);
|
||||||
|
compile_time_assert(ulint{BTR_SEARCH_LEAF} == ulint{RW_S_LATCH});
|
||||||
|
compile_time_assert(ulint{BTR_MODIFY_LEAF} == ulint{RW_X_LATCH});
|
||||||
|
|
||||||
cursor->n_fields = info->n_fields;
|
cursor->n_fields = info->n_fields;
|
||||||
cursor->n_bytes = info->n_bytes;
|
cursor->n_bytes = info->n_bytes;
|
||||||
|
|
||||||
|
@@ -2689,6 +2689,18 @@ re_evict:
|
|||||||
&& mode != BUF_GET_IF_IN_POOL_OR_WATCH) {
|
&& mode != BUF_GET_IF_IN_POOL_OR_WATCH) {
|
||||||
} else if (!ibuf_debug || recv_recovery_is_on()) {
|
} else if (!ibuf_debug || recv_recovery_is_on()) {
|
||||||
} else if (fil_space_t* space = fil_space_t::get(page_id.space())) {
|
} else if (fil_space_t* space = fil_space_t::get(page_id.space())) {
|
||||||
|
for (ulint i = 0; i < mtr->get_savepoint(); i++) {
|
||||||
|
if (buf_block_t* b = mtr->block_at_savepoint(i)) {
|
||||||
|
if (b->page.oldest_modification() > 2
|
||||||
|
&& b->page.lock.have_any()) {
|
||||||
|
/* We are holding a dirty page latch
|
||||||
|
that would hang buf_flush_sync(). */
|
||||||
|
space->release();
|
||||||
|
goto re_evict_fail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Try to evict the block from the buffer pool, to use the
|
/* Try to evict the block from the buffer pool, to use the
|
||||||
insert buffer (change buffer) as much as possible. */
|
insert buffer (change buffer) as much as possible. */
|
||||||
|
|
||||||
@@ -2730,9 +2742,9 @@ re_evict:
|
|||||||
|
|
||||||
/* Failed to evict the page; change it directly */
|
/* Failed to evict the page; change it directly */
|
||||||
}
|
}
|
||||||
|
re_evict_fail:
|
||||||
#endif /* UNIV_DEBUG || UNIV_IBUF_DEBUG */
|
#endif /* UNIV_DEBUG || UNIV_IBUF_DEBUG */
|
||||||
|
|
||||||
ut_ad(state > buf_page_t::FREED);
|
|
||||||
if (UNIV_UNLIKELY(state < buf_page_t::UNFIXED)) {
|
if (UNIV_UNLIKELY(state < buf_page_t::UNFIXED)) {
|
||||||
goto ignore_block;
|
goto ignore_block;
|
||||||
}
|
}
|
||||||
@@ -2788,8 +2800,7 @@ ibuf_merge_corrupted:
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (rw_latch == RW_X_LATCH) {
|
if (rw_latch == RW_X_LATCH) {
|
||||||
mtr->memo_push(block, MTR_MEMO_PAGE_X_FIX);
|
goto get_latch_valid;
|
||||||
goto got_latch;
|
|
||||||
} else {
|
} else {
|
||||||
block->page.lock.x_unlock();
|
block->page.lock.x_unlock();
|
||||||
goto get_latch;
|
goto get_latch;
|
||||||
@@ -2797,12 +2808,10 @@ ibuf_merge_corrupted:
|
|||||||
} else {
|
} else {
|
||||||
get_latch:
|
get_latch:
|
||||||
switch (rw_latch) {
|
switch (rw_latch) {
|
||||||
mtr_memo_type_t fix_type;
|
|
||||||
case RW_NO_LATCH:
|
case RW_NO_LATCH:
|
||||||
mtr->memo_push(block, MTR_MEMO_BUF_FIX);
|
mtr->memo_push(block, MTR_MEMO_BUF_FIX);
|
||||||
return block;
|
return block;
|
||||||
case RW_S_LATCH:
|
case RW_S_LATCH:
|
||||||
fix_type = MTR_MEMO_PAGE_S_FIX;
|
|
||||||
block->page.lock.s_lock();
|
block->page.lock.s_lock();
|
||||||
ut_ad(!block->page.is_read_fixed());
|
ut_ad(!block->page.is_read_fixed());
|
||||||
if (UNIV_UNLIKELY(block->page.id() != page_id)) {
|
if (UNIV_UNLIKELY(block->page.id() != page_id)) {
|
||||||
@@ -2811,13 +2820,12 @@ get_latch:
|
|||||||
goto page_id_mismatch;
|
goto page_id_mismatch;
|
||||||
}
|
}
|
||||||
get_latch_valid:
|
get_latch_valid:
|
||||||
mtr->memo_push(block, fix_type);
|
mtr->memo_push(block, mtr_memo_type_t(rw_latch));
|
||||||
#ifdef BTR_CUR_HASH_ADAPT
|
#ifdef BTR_CUR_HASH_ADAPT
|
||||||
btr_search_drop_page_hash_index(block, true);
|
btr_search_drop_page_hash_index(block, true);
|
||||||
#endif /* BTR_CUR_HASH_ADAPT */
|
#endif /* BTR_CUR_HASH_ADAPT */
|
||||||
break;
|
break;
|
||||||
case RW_SX_LATCH:
|
case RW_SX_LATCH:
|
||||||
fix_type = MTR_MEMO_PAGE_SX_FIX;
|
|
||||||
block->page.lock.u_lock();
|
block->page.lock.u_lock();
|
||||||
ut_ad(!block->page.is_io_fixed());
|
ut_ad(!block->page.is_io_fixed());
|
||||||
if (UNIV_UNLIKELY(block->page.id() != page_id)) {
|
if (UNIV_UNLIKELY(block->page.id() != page_id)) {
|
||||||
@@ -2827,7 +2835,6 @@ get_latch_valid:
|
|||||||
goto get_latch_valid;
|
goto get_latch_valid;
|
||||||
default:
|
default:
|
||||||
ut_ad(rw_latch == RW_X_LATCH);
|
ut_ad(rw_latch == RW_X_LATCH);
|
||||||
fix_type = MTR_MEMO_PAGE_X_FIX;
|
|
||||||
if (block->page.lock.x_lock_upgraded()) {
|
if (block->page.lock.x_lock_upgraded()) {
|
||||||
ut_ad(block->page.id() == page_id);
|
ut_ad(block->page.id() == page_id);
|
||||||
block->unfix();
|
block->unfix();
|
||||||
@@ -2840,7 +2847,6 @@ get_latch_valid:
|
|||||||
goto get_latch_valid;
|
goto get_latch_valid;
|
||||||
}
|
}
|
||||||
|
|
||||||
got_latch:
|
|
||||||
ut_ad(page_id_t(page_get_space_id(block->page.frame),
|
ut_ad(page_id_t(page_get_space_id(block->page.frame),
|
||||||
page_get_page_no(block->page.frame))
|
page_get_page_no(block->page.frame))
|
||||||
== page_id);
|
== page_id);
|
||||||
@@ -3029,8 +3035,7 @@ bool buf_page_optimistic_get(ulint rw_latch, buf_block_t *block,
|
|||||||
ut_ad(!block->page.is_read_fixed());
|
ut_ad(!block->page.is_read_fixed());
|
||||||
block->page.set_accessed();
|
block->page.set_accessed();
|
||||||
buf_page_make_young_if_needed(&block->page);
|
buf_page_make_young_if_needed(&block->page);
|
||||||
mtr->memo_push(block, rw_latch == RW_S_LATCH
|
mtr->memo_push(block, mtr_memo_type_t(rw_latch));
|
||||||
? MTR_MEMO_PAGE_S_FIX : MTR_MEMO_PAGE_X_FIX);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ut_d(if (!(++buf_dbg_counter % 5771)) buf_pool.validate());
|
ut_d(if (!(++buf_dbg_counter % 5771)) buf_pool.validate());
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
|
|
||||||
Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
|
Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
|
||||||
Copyright (c) 2017, 2022, MariaDB Corporation.
|
Copyright (c) 2017, 2023, MariaDB Corporation.
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify it under
|
This program is free software; you can redistribute it and/or modify it under
|
||||||
the terms of the GNU General Public License as published by the Free Software
|
the terms of the GNU General Public License as published by the Free Software
|
||||||
@@ -725,7 +725,7 @@ dict_build_field_def_step(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/***************************************************************//**
|
/***************************************************************//**
|
||||||
Creates an index tree for the index if it is not a member of a cluster.
|
Creates an index tree for the index.
|
||||||
@return DB_SUCCESS or DB_OUT_OF_FILE_SPACE */
|
@return DB_SUCCESS or DB_OUT_OF_FILE_SPACE */
|
||||||
static MY_ATTRIBUTE((nonnull, warn_unused_result))
|
static MY_ATTRIBUTE((nonnull, warn_unused_result))
|
||||||
dberr_t
|
dberr_t
|
||||||
@@ -758,9 +758,8 @@ dict_create_index_tree_step(
|
|||||||
pcur.btr_cur.page_cur.index =
|
pcur.btr_cur.page_cur.index =
|
||||||
UT_LIST_GET_FIRST(dict_sys.sys_indexes->indexes);
|
UT_LIST_GET_FIRST(dict_sys.sys_indexes->indexes);
|
||||||
|
|
||||||
dberr_t err =
|
dberr_t err = btr_pcur_open(search_tuple, PAGE_CUR_L, BTR_MODIFY_LEAF,
|
||||||
btr_pcur_open(search_tuple, PAGE_CUR_L, BTR_MODIFY_LEAF,
|
&pcur, &mtr);
|
||||||
&pcur, 0, &mtr);
|
|
||||||
|
|
||||||
if (err != DB_SUCCESS) {
|
if (err != DB_SUCCESS) {
|
||||||
func_exit:
|
func_exit:
|
||||||
@@ -771,10 +770,25 @@ func_exit:
|
|||||||
btr_pcur_move_to_next_user_rec(&pcur, &mtr);
|
btr_pcur_move_to_next_user_rec(&pcur, &mtr);
|
||||||
|
|
||||||
if (UNIV_UNLIKELY(btr_pcur_is_after_last_on_page(&pcur))) {
|
if (UNIV_UNLIKELY(btr_pcur_is_after_last_on_page(&pcur))) {
|
||||||
|
corrupted:
|
||||||
err = DB_CORRUPTION;
|
err = DB_CORRUPTION;
|
||||||
goto func_exit;
|
goto func_exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ulint len;
|
||||||
|
byte* data = rec_get_nth_field_old(btr_pcur_get_rec(&pcur),
|
||||||
|
DICT_FLD__SYS_INDEXES__ID,
|
||||||
|
&len);
|
||||||
|
if (UNIV_UNLIKELY(len != 8 || mach_read_from_8(data) != index->id)) {
|
||||||
|
goto corrupted;
|
||||||
|
}
|
||||||
|
|
||||||
|
data = rec_get_nth_field_old(btr_pcur_get_rec(&pcur),
|
||||||
|
DICT_FLD__SYS_INDEXES__PAGE_NO, &len);
|
||||||
|
if (len != 4) {
|
||||||
|
goto corrupted;
|
||||||
|
}
|
||||||
|
|
||||||
if (index->is_readable()) {
|
if (index->is_readable()) {
|
||||||
index->set_modified(mtr);
|
index->set_modified(mtr);
|
||||||
|
|
||||||
@@ -787,11 +801,6 @@ func_exit:
|
|||||||
err = DB_OUT_OF_FILE_SPACE; );
|
err = DB_OUT_OF_FILE_SPACE; );
|
||||||
}
|
}
|
||||||
|
|
||||||
ulint len;
|
|
||||||
byte* data = rec_get_nth_field_old(btr_pcur_get_rec(&pcur),
|
|
||||||
DICT_FLD__SYS_INDEXES__PAGE_NO,
|
|
||||||
&len);
|
|
||||||
ut_ad(len == 4);
|
|
||||||
mtr.write<4,mtr_t::MAYBE_NOP>(*btr_pcur_get_block(&pcur), data,
|
mtr.write<4,mtr_t::MAYBE_NOP>(*btr_pcur_get_block(&pcur), data,
|
||||||
node->page_no);
|
node->page_no);
|
||||||
goto func_exit;
|
goto func_exit;
|
||||||
|
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
|
Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
|
||||||
Copyright (c) 2012, Facebook Inc.
|
Copyright (c) 2012, Facebook Inc.
|
||||||
Copyright (c) 2013, 2022, MariaDB Corporation.
|
Copyright (c) 2013, 2023, MariaDB Corporation.
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify it under
|
This program is free software; you can redistribute it and/or modify it under
|
||||||
the terms of the GNU General Public License as published by the Free Software
|
the terms of the GNU General Public License as published by the Free Software
|
||||||
@@ -4149,8 +4149,7 @@ void dict_set_corrupted(dict_index_t *index, const char *ctx)
|
|||||||
dict_index_copy_types(tuple, sys_index, 2);
|
dict_index_copy_types(tuple, sys_index, 2);
|
||||||
cursor.page_cur.index = sys_index;
|
cursor.page_cur.index = sys_index;
|
||||||
|
|
||||||
if (btr_cur_search_to_nth_level(0, tuple, PAGE_CUR_LE,
|
if (cursor.search_leaf(tuple, PAGE_CUR_LE, BTR_MODIFY_LEAF, &mtr)
|
||||||
BTR_MODIFY_LEAF, &cursor, &mtr)
|
|
||||||
!= DB_SUCCESS) {
|
!= DB_SUCCESS) {
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
@@ -4225,8 +4224,7 @@ dict_index_set_merge_threshold(
|
|||||||
dict_index_copy_types(tuple, sys_index, 2);
|
dict_index_copy_types(tuple, sys_index, 2);
|
||||||
cursor.page_cur.index = sys_index;
|
cursor.page_cur.index = sys_index;
|
||||||
|
|
||||||
if (btr_cur_search_to_nth_level(0, tuple, PAGE_CUR_GE,
|
if (cursor.search_leaf(tuple, PAGE_CUR_GE, BTR_MODIFY_LEAF, &mtr)
|
||||||
BTR_MODIFY_LEAF, &cursor, &mtr)
|
|
||||||
!= DB_SUCCESS) {
|
!= DB_SUCCESS) {
|
||||||
goto func_exit;
|
goto func_exit;
|
||||||
}
|
}
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
|
|
||||||
Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
|
Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
|
||||||
Copyright (c) 2016, 2022, MariaDB Corporation.
|
Copyright (c) 2016, 2023, MariaDB Corporation.
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify it under
|
This program is free software; you can redistribute it and/or modify it under
|
||||||
the terms of the GNU General Public License as published by the Free Software
|
the terms of the GNU General Public License as published by the Free Software
|
||||||
@@ -1319,7 +1319,7 @@ static dberr_t dict_load_columns(dict_table_t *table, unsigned use_uncommitted,
|
|||||||
dict_index_copy_types(&tuple, sys_index, 1);
|
dict_index_copy_types(&tuple, sys_index, 1);
|
||||||
pcur.btr_cur.page_cur.index = sys_index;
|
pcur.btr_cur.page_cur.index = sys_index;
|
||||||
|
|
||||||
dberr_t err = btr_pcur_open_on_user_rec(&tuple, PAGE_CUR_GE,
|
dberr_t err = btr_pcur_open_on_user_rec(&tuple,
|
||||||
BTR_SEARCH_LEAF, &pcur, &mtr);
|
BTR_SEARCH_LEAF, &pcur, &mtr);
|
||||||
if (err != DB_SUCCESS) {
|
if (err != DB_SUCCESS) {
|
||||||
goto func_exit;
|
goto func_exit;
|
||||||
@@ -1450,7 +1450,7 @@ dict_load_virtual_col(dict_table_t *table, bool uncommitted, ulint nth_v_col)
|
|||||||
dict_index_copy_types(&tuple, sys_virtual_index, 2);
|
dict_index_copy_types(&tuple, sys_virtual_index, 2);
|
||||||
pcur.btr_cur.page_cur.index = sys_virtual_index;
|
pcur.btr_cur.page_cur.index = sys_virtual_index;
|
||||||
|
|
||||||
dberr_t err = btr_pcur_open_on_user_rec(&tuple, PAGE_CUR_GE,
|
dberr_t err = btr_pcur_open_on_user_rec(&tuple,
|
||||||
BTR_SEARCH_LEAF, &pcur, &mtr);
|
BTR_SEARCH_LEAF, &pcur, &mtr);
|
||||||
if (err != DB_SUCCESS) {
|
if (err != DB_SUCCESS) {
|
||||||
goto func_exit;
|
goto func_exit;
|
||||||
@@ -1690,8 +1690,7 @@ static dberr_t dict_load_fields(dict_index_t *index, bool uncommitted,
|
|||||||
dict_index_copy_types(&tuple, sys_index, 1);
|
dict_index_copy_types(&tuple, sys_index, 1);
|
||||||
pcur.btr_cur.page_cur.index = sys_index;
|
pcur.btr_cur.page_cur.index = sys_index;
|
||||||
|
|
||||||
dberr_t error = btr_pcur_open_on_user_rec(&tuple,
|
dberr_t error = btr_pcur_open_on_user_rec(&tuple, BTR_SEARCH_LEAF,
|
||||||
PAGE_CUR_GE, BTR_SEARCH_LEAF,
|
|
||||||
&pcur, &mtr);
|
&pcur, &mtr);
|
||||||
if (error != DB_SUCCESS) {
|
if (error != DB_SUCCESS) {
|
||||||
goto func_exit;
|
goto func_exit;
|
||||||
@@ -1949,8 +1948,7 @@ dberr_t dict_load_indexes(dict_table_t *table, bool uncommitted,
|
|||||||
dict_index_copy_types(&tuple, sys_index, 1);
|
dict_index_copy_types(&tuple, sys_index, 1);
|
||||||
pcur.btr_cur.page_cur.index = sys_index;
|
pcur.btr_cur.page_cur.index = sys_index;
|
||||||
|
|
||||||
dberr_t error = btr_pcur_open_on_user_rec(&tuple,
|
dberr_t error = btr_pcur_open_on_user_rec(&tuple, BTR_SEARCH_LEAF,
|
||||||
PAGE_CUR_GE, BTR_SEARCH_LEAF,
|
|
||||||
&pcur, &mtr);
|
&pcur, &mtr);
|
||||||
if (error != DB_SUCCESS) {
|
if (error != DB_SUCCESS) {
|
||||||
goto func_exit;
|
goto func_exit;
|
||||||
@@ -2347,7 +2345,7 @@ static dict_table_t *dict_load_table_one(const span<const char> &name,
|
|||||||
bool uncommitted = false;
|
bool uncommitted = false;
|
||||||
reload:
|
reload:
|
||||||
mtr.start();
|
mtr.start();
|
||||||
dberr_t err = btr_pcur_open_on_user_rec(&tuple, PAGE_CUR_GE,
|
dberr_t err = btr_pcur_open_on_user_rec(&tuple,
|
||||||
BTR_SEARCH_LEAF, &pcur, &mtr);
|
BTR_SEARCH_LEAF, &pcur, &mtr);
|
||||||
|
|
||||||
if (err != DB_SUCCESS || !btr_pcur_is_on_user_rec(&pcur)) {
|
if (err != DB_SUCCESS || !btr_pcur_is_on_user_rec(&pcur)) {
|
||||||
@@ -2605,8 +2603,7 @@ dict_load_table_on_id(
|
|||||||
|
|
||||||
dict_table_t* table = nullptr;
|
dict_table_t* table = nullptr;
|
||||||
|
|
||||||
if (btr_pcur_open_on_user_rec(&tuple, PAGE_CUR_GE,
|
if (btr_pcur_open_on_user_rec(&tuple, BTR_SEARCH_LEAF, &pcur, &mtr)
|
||||||
BTR_SEARCH_LEAF, &pcur, &mtr)
|
|
||||||
== DB_SUCCESS
|
== DB_SUCCESS
|
||||||
&& btr_pcur_is_on_user_rec(&pcur)) {
|
&& btr_pcur_is_on_user_rec(&pcur)) {
|
||||||
/*---------------------------------------------------*/
|
/*---------------------------------------------------*/
|
||||||
@@ -2712,7 +2709,7 @@ static dberr_t dict_load_foreign_cols(dict_foreign_t *foreign, trx_id_t trx_id)
|
|||||||
pcur.btr_cur.page_cur.index = sys_index;
|
pcur.btr_cur.page_cur.index = sys_index;
|
||||||
|
|
||||||
mem_heap_t* heap = nullptr;
|
mem_heap_t* heap = nullptr;
|
||||||
dberr_t err = btr_pcur_open_on_user_rec(&tuple, PAGE_CUR_GE,
|
dberr_t err = btr_pcur_open_on_user_rec(&tuple,
|
||||||
BTR_SEARCH_LEAF, &pcur, &mtr);
|
BTR_SEARCH_LEAF, &pcur, &mtr);
|
||||||
if (err != DB_SUCCESS) {
|
if (err != DB_SUCCESS) {
|
||||||
goto func_exit;
|
goto func_exit;
|
||||||
@@ -2889,7 +2886,7 @@ dict_load_foreign(
|
|||||||
mtr.start();
|
mtr.start();
|
||||||
|
|
||||||
mem_heap_t* heap = nullptr;
|
mem_heap_t* heap = nullptr;
|
||||||
dberr_t err = btr_pcur_open_on_user_rec(&tuple, PAGE_CUR_GE,
|
dberr_t err = btr_pcur_open_on_user_rec(&tuple,
|
||||||
BTR_SEARCH_LEAF, &pcur, &mtr);
|
BTR_SEARCH_LEAF, &pcur, &mtr);
|
||||||
if (err != DB_SUCCESS) {
|
if (err != DB_SUCCESS) {
|
||||||
goto err_exit;
|
goto err_exit;
|
||||||
@@ -3100,7 +3097,7 @@ start_load:
|
|||||||
dict_index_copy_types(&tuple, sec_index, 1);
|
dict_index_copy_types(&tuple, sec_index, 1);
|
||||||
pcur.btr_cur.page_cur.index = sec_index;
|
pcur.btr_cur.page_cur.index = sec_index;
|
||||||
|
|
||||||
dberr_t err = btr_pcur_open_on_user_rec(&tuple, PAGE_CUR_GE,
|
dberr_t err = btr_pcur_open_on_user_rec(&tuple,
|
||||||
BTR_SEARCH_LEAF, &pcur, &mtr);
|
BTR_SEARCH_LEAF, &pcur, &mtr);
|
||||||
if (err != DB_SUCCESS) {
|
if (err != DB_SUCCESS) {
|
||||||
DBUG_RETURN(err);
|
DBUG_RETURN(err);
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
|
|
||||||
Copyright (c) 2009, 2019, Oracle and/or its affiliates. All Rights Reserved.
|
Copyright (c) 2009, 2019, Oracle and/or its affiliates. All Rights Reserved.
|
||||||
Copyright (c) 2015, 2022, MariaDB Corporation.
|
Copyright (c) 2015, 2023, MariaDB Corporation.
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify it under
|
This program is free software; you can redistribute it and/or modify it under
|
||||||
the terms of the GNU General Public License as published by the Free Software
|
the terms of the GNU General Public License as published by the Free Software
|
||||||
@@ -1697,7 +1697,7 @@ static dberr_t page_cur_open_level(page_cur_t *page_cur, ulint level,
|
|||||||
static dberr_t btr_pcur_open_level(btr_pcur_t *pcur, ulint level, mtr_t *mtr,
|
static dberr_t btr_pcur_open_level(btr_pcur_t *pcur, ulint level, mtr_t *mtr,
|
||||||
dict_index_t *index)
|
dict_index_t *index)
|
||||||
{
|
{
|
||||||
pcur->latch_mode= BTR_SEARCH_TREE;
|
pcur->latch_mode= BTR_SEARCH_LEAF;
|
||||||
pcur->search_mode= PAGE_CUR_G;
|
pcur->search_mode= PAGE_CUR_G;
|
||||||
pcur->pos_state= BTR_PCUR_IS_POSITIONED;
|
pcur->pos_state= BTR_PCUR_IS_POSITIONED;
|
||||||
pcur->btr_cur.page_cur.index= index;
|
pcur->btr_cur.page_cur.index= index;
|
||||||
|
@@ -1429,7 +1429,7 @@ inline void mtr_t::log_file_op(mfile_type_t type, uint32_t space_id,
|
|||||||
ut_ad(strchr(path, '/'));
|
ut_ad(strchr(path, '/'));
|
||||||
ut_ad(!strcmp(&path[strlen(path) - strlen(DOT_IBD)], DOT_IBD));
|
ut_ad(!strcmp(&path[strlen(path) - strlen(DOT_IBD)], DOT_IBD));
|
||||||
|
|
||||||
flag_modified();
|
m_modifications= true;
|
||||||
if (!is_logged())
|
if (!is_logged())
|
||||||
return;
|
return;
|
||||||
m_last= nullptr;
|
m_last= nullptr;
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
|
|
||||||
Copyright (c) 1995, 2016, Oracle and/or its affiliates. All Rights Reserved.
|
Copyright (c) 1995, 2016, Oracle and/or its affiliates. All Rights Reserved.
|
||||||
Copyright (c) 2017, 2022, MariaDB Corporation.
|
Copyright (c) 2017, 2023, MariaDB Corporation.
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify it under
|
This program is free software; you can redistribute it and/or modify it under
|
||||||
the terms of the GNU General Public License as published by the Free Software
|
the terms of the GNU General Public License as published by the Free Software
|
||||||
@@ -122,15 +122,22 @@ MY_ATTRIBUTE((nonnull, warn_unused_result))
|
|||||||
static buf_block_t *fsp_get_header(const fil_space_t *space, mtr_t *mtr,
|
static buf_block_t *fsp_get_header(const fil_space_t *space, mtr_t *mtr,
|
||||||
dberr_t *err)
|
dberr_t *err)
|
||||||
{
|
{
|
||||||
buf_block_t *block= buf_page_get_gen(page_id_t(space->id, 0),
|
const page_id_t id{space->id, 0};
|
||||||
space->zip_size(), RW_SX_LATCH,
|
buf_block_t *block= mtr->get_already_latched(id, MTR_MEMO_PAGE_SX_FIX);
|
||||||
nullptr, BUF_GET_POSSIBLY_FREED,
|
if (block)
|
||||||
mtr, err);
|
*err= DB_SUCCESS;
|
||||||
if (block && space->id != mach_read_from_4(FSP_HEADER_OFFSET + FSP_SPACE_ID +
|
else
|
||||||
block->page.frame))
|
|
||||||
{
|
{
|
||||||
*err= DB_CORRUPTION;
|
block= buf_page_get_gen(id, space->zip_size(), RW_SX_LATCH,
|
||||||
block= nullptr;
|
nullptr, BUF_GET_POSSIBLY_FREED,
|
||||||
|
mtr, err);
|
||||||
|
if (block &&
|
||||||
|
space->id != mach_read_from_4(FSP_HEADER_OFFSET + FSP_SPACE_ID +
|
||||||
|
block->page.frame))
|
||||||
|
{
|
||||||
|
*err= DB_CORRUPTION;
|
||||||
|
block= nullptr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return block;
|
return block;
|
||||||
}
|
}
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
|
|
||||||
Copyright (c) 2016, 2018, Oracle and/or its affiliates. All Rights Reserved.
|
Copyright (c) 2016, 2018, Oracle and/or its affiliates. All Rights Reserved.
|
||||||
Copyright (c) 2017, 2022, MariaDB Corporation.
|
Copyright (c) 2017, 2023, MariaDB Corporation.
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify it under
|
This program is free software; you can redistribute it and/or modify it under
|
||||||
the terms of the GNU General Public License as published by the Free Software
|
the terms of the GNU General Public License as published by the Free Software
|
||||||
@@ -44,7 +44,6 @@ Created 2014/01/16 Jimmy Yang
|
|||||||
static
|
static
|
||||||
bool
|
bool
|
||||||
rtr_cur_restore_position(
|
rtr_cur_restore_position(
|
||||||
ulint latch_mode, /*!< in: BTR_SEARCH_LEAF, ... */
|
|
||||||
btr_cur_t* cursor, /*!< in: detached persistent cursor */
|
btr_cur_t* cursor, /*!< in: detached persistent cursor */
|
||||||
ulint level, /*!< in: index level */
|
ulint level, /*!< in: index level */
|
||||||
mtr_t* mtr); /*!< in: mtr */
|
mtr_t* mtr); /*!< in: mtr */
|
||||||
@@ -74,6 +73,70 @@ rtr_adjust_parent_path(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Latches the leaf page or pages requested.
|
||||||
|
@param[in] block_savepoint leaf page where the search converged
|
||||||
|
@param[in] latch_mode BTR_SEARCH_LEAF, ...
|
||||||
|
@param[in] cursor cursor
|
||||||
|
@param[in] mtr mini-transaction */
|
||||||
|
static void
|
||||||
|
rtr_latch_leaves(
|
||||||
|
ulint block_savepoint,
|
||||||
|
btr_latch_mode latch_mode,
|
||||||
|
btr_cur_t* cursor,
|
||||||
|
mtr_t* mtr)
|
||||||
|
{
|
||||||
|
compile_time_assert(int(MTR_MEMO_PAGE_S_FIX) == int(RW_S_LATCH));
|
||||||
|
compile_time_assert(int(MTR_MEMO_PAGE_X_FIX) == int(RW_X_LATCH));
|
||||||
|
compile_time_assert(int(MTR_MEMO_PAGE_SX_FIX) == int(RW_SX_LATCH));
|
||||||
|
|
||||||
|
buf_block_t* block = mtr->at_savepoint(block_savepoint);
|
||||||
|
|
||||||
|
ut_ad(block->page.id().space() == cursor->index()->table->space->id);
|
||||||
|
ut_ad(block->page.in_file());
|
||||||
|
ut_ad(mtr->memo_contains_flagged(&cursor->index()->lock,
|
||||||
|
MTR_MEMO_S_LOCK
|
||||||
|
| MTR_MEMO_X_LOCK
|
||||||
|
| MTR_MEMO_SX_LOCK));
|
||||||
|
|
||||||
|
switch (latch_mode) {
|
||||||
|
uint32_t left_page_no;
|
||||||
|
uint32_t right_page_no;
|
||||||
|
default:
|
||||||
|
ut_ad(latch_mode == BTR_CONT_MODIFY_TREE);
|
||||||
|
break;
|
||||||
|
case BTR_MODIFY_TREE:
|
||||||
|
/* It is exclusive for other operations which calls
|
||||||
|
btr_page_set_prev() */
|
||||||
|
ut_ad(mtr->memo_contains_flagged(&cursor->index()->lock,
|
||||||
|
MTR_MEMO_X_LOCK
|
||||||
|
| MTR_MEMO_SX_LOCK));
|
||||||
|
/* x-latch also siblings from left to right */
|
||||||
|
left_page_no = btr_page_get_prev(block->page.frame);
|
||||||
|
|
||||||
|
if (left_page_no != FIL_NULL) {
|
||||||
|
btr_block_get(*cursor->index(), left_page_no, RW_X_LATCH,
|
||||||
|
true, mtr);
|
||||||
|
}
|
||||||
|
|
||||||
|
mtr->upgrade_buffer_fix(block_savepoint, RW_X_LATCH);
|
||||||
|
|
||||||
|
right_page_no = btr_page_get_next(block->page.frame);
|
||||||
|
|
||||||
|
if (right_page_no != FIL_NULL) {
|
||||||
|
btr_block_get(*cursor->index(), right_page_no,
|
||||||
|
RW_X_LATCH, true, mtr);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case BTR_SEARCH_LEAF:
|
||||||
|
case BTR_MODIFY_LEAF:
|
||||||
|
rw_lock_type_t mode =
|
||||||
|
rw_lock_type_t(latch_mode & (RW_X_LATCH | RW_S_LATCH));
|
||||||
|
static_assert(int{RW_S_LATCH} == int{BTR_SEARCH_LEAF}, "");
|
||||||
|
static_assert(int{RW_X_LATCH} == int{BTR_MODIFY_LEAF}, "");
|
||||||
|
mtr->upgrade_buffer_fix(block_savepoint, mode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*************************************************************//**
|
/*************************************************************//**
|
||||||
Find the next matching record. This function is used by search
|
Find the next matching record. This function is used by search
|
||||||
or record locating during index delete/update.
|
or record locating during index delete/update.
|
||||||
@@ -135,6 +198,7 @@ rtr_pcur_getnext_from_path(
|
|||||||
&& (my_latch_mode | 4) == BTR_CONT_MODIFY_TREE;
|
&& (my_latch_mode | 4) == BTR_CONT_MODIFY_TREE;
|
||||||
|
|
||||||
if (!index_locked) {
|
if (!index_locked) {
|
||||||
|
ut_ad(mtr->is_empty());
|
||||||
mtr_s_lock_index(index, mtr);
|
mtr_s_lock_index(index, mtr);
|
||||||
} else {
|
} else {
|
||||||
ut_ad(mtr->memo_contains_flagged(&index->lock,
|
ut_ad(mtr->memo_contains_flagged(&index->lock,
|
||||||
@@ -154,14 +218,12 @@ rtr_pcur_getnext_from_path(
|
|||||||
node_seq_t path_ssn;
|
node_seq_t path_ssn;
|
||||||
const page_t* page;
|
const page_t* page;
|
||||||
rw_lock_type_t rw_latch;
|
rw_lock_type_t rw_latch;
|
||||||
ulint tree_idx;
|
|
||||||
|
|
||||||
mysql_mutex_lock(&rtr_info->rtr_path_mutex);
|
mysql_mutex_lock(&rtr_info->rtr_path_mutex);
|
||||||
next_rec = rtr_info->path->back();
|
next_rec = rtr_info->path->back();
|
||||||
rtr_info->path->pop_back();
|
rtr_info->path->pop_back();
|
||||||
level = next_rec.level;
|
level = next_rec.level;
|
||||||
path_ssn = next_rec.seq_no;
|
path_ssn = next_rec.seq_no;
|
||||||
tree_idx = btr_cur->tree_height - level - 1;
|
|
||||||
|
|
||||||
/* Maintain the parent path info as well, if needed */
|
/* Maintain the parent path info as well, if needed */
|
||||||
if (need_parent && !skip_parent && !new_split) {
|
if (need_parent && !skip_parent && !new_split) {
|
||||||
@@ -223,37 +285,15 @@ rtr_pcur_getnext_from_path(
|
|||||||
rw_latch = RW_X_LATCH;
|
rw_latch = RW_X_LATCH;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Release previous locked blocks */
|
if (my_latch_mode == BTR_MODIFY_LEAF) {
|
||||||
if (my_latch_mode != BTR_SEARCH_LEAF) {
|
mtr->rollback_to_savepoint(1);
|
||||||
for (ulint idx = 0; idx < btr_cur->tree_height;
|
|
||||||
idx++) {
|
|
||||||
if (rtr_info->tree_blocks[idx]) {
|
|
||||||
mtr_release_block_at_savepoint(
|
|
||||||
mtr,
|
|
||||||
rtr_info->tree_savepoints[idx],
|
|
||||||
rtr_info->tree_blocks[idx]);
|
|
||||||
rtr_info->tree_blocks[idx] = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (ulint idx = RTR_MAX_LEVELS; idx < RTR_MAX_LEVELS + 3;
|
|
||||||
idx++) {
|
|
||||||
if (rtr_info->tree_blocks[idx]) {
|
|
||||||
mtr_release_block_at_savepoint(
|
|
||||||
mtr,
|
|
||||||
rtr_info->tree_savepoints[idx],
|
|
||||||
rtr_info->tree_blocks[idx]);
|
|
||||||
rtr_info->tree_blocks[idx] = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* set up savepoint to record any locks to be taken */
|
|
||||||
rtr_info->tree_savepoints[tree_idx] = mtr_set_savepoint(mtr);
|
|
||||||
|
|
||||||
ut_ad((my_latch_mode | 4) == BTR_CONT_MODIFY_TREE
|
ut_ad((my_latch_mode | 4) == BTR_CONT_MODIFY_TREE
|
||||||
|| !page_is_leaf(btr_cur_get_page(btr_cur))
|
|| !page_is_leaf(btr_cur_get_page(btr_cur))
|
||||||
|| !btr_cur->page_cur.block->page.lock.have_any());
|
|| !btr_cur->page_cur.block->page.lock.have_any());
|
||||||
|
|
||||||
|
const auto block_savepoint = mtr->get_savepoint();
|
||||||
block = buf_page_get_gen(
|
block = buf_page_get_gen(
|
||||||
page_id_t(index->table->space_id,
|
page_id_t(index->table->space_id,
|
||||||
next_rec.page_no), zip_size,
|
next_rec.page_no), zip_size,
|
||||||
@@ -264,8 +304,6 @@ rtr_pcur_getnext_from_path(
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
rtr_info->tree_blocks[tree_idx] = block;
|
|
||||||
|
|
||||||
page = buf_block_get_frame(block);
|
page = buf_block_get_frame(block);
|
||||||
page_ssn = page_get_ssn_id(page);
|
page_ssn = page_get_ssn_id(page);
|
||||||
|
|
||||||
@@ -396,24 +434,23 @@ rtr_pcur_getnext_from_path(
|
|||||||
|
|
||||||
if (found) {
|
if (found) {
|
||||||
if (level == target_level) {
|
if (level == target_level) {
|
||||||
page_cur_t* r_cur;;
|
ut_ad(block
|
||||||
|
== mtr->at_savepoint(block_savepoint));
|
||||||
|
|
||||||
if (my_latch_mode == BTR_MODIFY_TREE
|
if (my_latch_mode == BTR_MODIFY_TREE
|
||||||
&& level == 0) {
|
&& level == 0) {
|
||||||
ut_ad(rw_latch == RW_NO_LATCH);
|
ut_ad(rw_latch == RW_NO_LATCH);
|
||||||
|
|
||||||
btr_cur_latch_leaves(
|
rtr_latch_leaves(
|
||||||
block,
|
block_savepoint,
|
||||||
BTR_MODIFY_TREE,
|
BTR_MODIFY_TREE,
|
||||||
btr_cur, mtr);
|
btr_cur, mtr);
|
||||||
}
|
}
|
||||||
|
|
||||||
r_cur = btr_cur_get_page_cur(btr_cur);
|
|
||||||
|
|
||||||
page_cur_position(
|
page_cur_position(
|
||||||
page_cur_get_rec(page_cursor),
|
page_cur_get_rec(page_cursor),
|
||||||
page_cur_get_block(page_cursor),
|
page_cur_get_block(page_cursor),
|
||||||
r_cur);
|
btr_cur_get_page_cur(btr_cur));
|
||||||
|
|
||||||
btr_cur->low_match = level != 0 ?
|
btr_cur->low_match = level != 0 ?
|
||||||
DICT_INDEX_SPATIAL_NODEPTR_SIZE + 1
|
DICT_INDEX_SPATIAL_NODEPTR_SIZE + 1
|
||||||
@@ -425,13 +462,7 @@ rtr_pcur_getnext_from_path(
|
|||||||
last node just located */
|
last node just located */
|
||||||
skip_parent = true;
|
skip_parent = true;
|
||||||
} else {
|
} else {
|
||||||
/* Release latch on the current page */
|
mtr->release_last_page();
|
||||||
ut_ad(rtr_info->tree_blocks[tree_idx]);
|
|
||||||
|
|
||||||
mtr_release_block_at_savepoint(
|
|
||||||
mtr, rtr_info->tree_savepoints[tree_idx],
|
|
||||||
rtr_info->tree_blocks[tree_idx]);
|
|
||||||
rtr_info->tree_blocks[tree_idx] = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} while (!rtr_info->path->empty());
|
} while (!rtr_info->path->empty());
|
||||||
@@ -509,50 +540,524 @@ static void rtr_compare_cursor_rec(const rec_t *rec, dict_index_t *index,
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
TRANSACTIONAL_TARGET
|
||||||
|
dberr_t rtr_search_to_nth_level(ulint level, const dtuple_t *tuple,
|
||||||
|
page_cur_mode_t mode,
|
||||||
|
btr_latch_mode latch_mode,
|
||||||
|
btr_cur_t *cur, mtr_t *mtr)
|
||||||
|
{
|
||||||
|
page_cur_mode_t page_mode;
|
||||||
|
page_cur_mode_t search_mode= PAGE_CUR_UNSUPP;
|
||||||
|
|
||||||
|
bool mbr_adj= false;
|
||||||
|
bool found= false;
|
||||||
|
dict_index_t *const index= cur->index();
|
||||||
|
|
||||||
|
mem_heap_t *heap= nullptr;
|
||||||
|
rec_offs offsets_[REC_OFFS_NORMAL_SIZE];
|
||||||
|
rec_offs *offsets= offsets_;
|
||||||
|
rec_offs_init(offsets_);
|
||||||
|
ut_ad(level == 0 || mode == PAGE_CUR_LE || RTREE_SEARCH_MODE(mode));
|
||||||
|
ut_ad(dict_index_check_search_tuple(index, tuple));
|
||||||
|
ut_ad(dtuple_check_typed(tuple));
|
||||||
|
ut_ad(index->is_spatial());
|
||||||
|
ut_ad(index->page != FIL_NULL);
|
||||||
|
|
||||||
|
MEM_UNDEFINED(&cur->up_match, sizeof cur->up_match);
|
||||||
|
MEM_UNDEFINED(&cur->up_bytes, sizeof cur->up_bytes);
|
||||||
|
MEM_UNDEFINED(&cur->low_match, sizeof cur->low_match);
|
||||||
|
MEM_UNDEFINED(&cur->low_bytes, sizeof cur->low_bytes);
|
||||||
|
ut_d(cur->up_match= ULINT_UNDEFINED);
|
||||||
|
ut_d(cur->low_match= ULINT_UNDEFINED);
|
||||||
|
|
||||||
|
const bool latch_by_caller= latch_mode & BTR_ALREADY_S_LATCHED;
|
||||||
|
|
||||||
|
ut_ad(!latch_by_caller
|
||||||
|
|| mtr->memo_contains_flagged(&index->lock, MTR_MEMO_S_LOCK
|
||||||
|
| MTR_MEMO_SX_LOCK));
|
||||||
|
latch_mode= BTR_LATCH_MODE_WITHOUT_FLAGS(latch_mode);
|
||||||
|
|
||||||
|
ut_ad(!latch_by_caller || latch_mode == BTR_SEARCH_LEAF ||
|
||||||
|
latch_mode == BTR_MODIFY_LEAF);
|
||||||
|
|
||||||
|
cur->flag= BTR_CUR_BINARY;
|
||||||
|
|
||||||
|
#ifndef BTR_CUR_ADAPT
|
||||||
|
buf_block_t *guess= nullptr;
|
||||||
|
#else
|
||||||
|
btr_search_t *const info= btr_search_get_info(index);
|
||||||
|
buf_block_t *guess= info->root_guess;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Store the position of the tree latch we push to mtr so that we
|
||||||
|
know how to release it when we have latched leaf node(s) */
|
||||||
|
|
||||||
|
const ulint savepoint= mtr->get_savepoint();
|
||||||
|
|
||||||
|
rw_lock_type_t upper_rw_latch, root_leaf_rw_latch= RW_NO_LATCH;
|
||||||
|
|
||||||
|
switch (latch_mode) {
|
||||||
|
case BTR_MODIFY_TREE:
|
||||||
|
mtr_x_lock_index(index, mtr);
|
||||||
|
upper_rw_latch= root_leaf_rw_latch= RW_X_LATCH;
|
||||||
|
break;
|
||||||
|
case BTR_CONT_MODIFY_TREE:
|
||||||
|
ut_ad(mtr->memo_contains_flagged(&index->lock, MTR_MEMO_X_LOCK |
|
||||||
|
MTR_MEMO_SX_LOCK));
|
||||||
|
upper_rw_latch= RW_X_LATCH;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ut_ad(latch_mode != BTR_MODIFY_PREV);
|
||||||
|
ut_ad(latch_mode != BTR_SEARCH_PREV);
|
||||||
|
if (!latch_by_caller)
|
||||||
|
mtr_s_lock_index(index, mtr);
|
||||||
|
upper_rw_latch= root_leaf_rw_latch= RW_S_LATCH;
|
||||||
|
if (latch_mode == BTR_MODIFY_LEAF)
|
||||||
|
root_leaf_rw_latch= RW_X_LATCH;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto root_savepoint= mtr->get_savepoint();
|
||||||
|
const ulint zip_size= index->table->space->zip_size();
|
||||||
|
|
||||||
|
/* Start with the root page. */
|
||||||
|
page_id_t page_id(index->table->space_id, index->page);
|
||||||
|
|
||||||
|
ulint up_match= 0, up_bytes= 0, low_match= 0, low_bytes= 0;
|
||||||
|
ulint height= ULINT_UNDEFINED;
|
||||||
|
|
||||||
|
/* We use these modified search modes on non-leaf levels of the
|
||||||
|
B-tree. These let us end up in the right B-tree leaf. In that leaf
|
||||||
|
we use the original search mode. */
|
||||||
|
|
||||||
|
switch (mode) {
|
||||||
|
case PAGE_CUR_GE:
|
||||||
|
page_mode= PAGE_CUR_L;
|
||||||
|
break;
|
||||||
|
case PAGE_CUR_G:
|
||||||
|
page_mode= PAGE_CUR_LE;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
#ifdef PAGE_CUR_LE_OR_EXTENDS
|
||||||
|
ut_ad(mode == PAGE_CUR_L || mode == PAGE_CUR_LE
|
||||||
|
|| RTREE_SEARCH_MODE(mode)
|
||||||
|
|| mode == PAGE_CUR_LE_OR_EXTENDS);
|
||||||
|
#else /* PAGE_CUR_LE_OR_EXTENDS */
|
||||||
|
ut_ad(mode == PAGE_CUR_L || mode == PAGE_CUR_LE
|
||||||
|
|| RTREE_SEARCH_MODE(mode));
|
||||||
|
#endif /* PAGE_CUR_LE_OR_EXTENDS */
|
||||||
|
page_mode= mode;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
search_loop:
|
||||||
|
auto buf_mode= BUF_GET;
|
||||||
|
ulint rw_latch= RW_NO_LATCH;
|
||||||
|
|
||||||
|
if (height)
|
||||||
|
{
|
||||||
|
/* We are about to fetch the root or a non-leaf page. */
|
||||||
|
if (latch_mode != BTR_MODIFY_TREE || height == level)
|
||||||
|
/* If doesn't have SX or X latch of index,
|
||||||
|
each page should be latched before reading. */
|
||||||
|
rw_latch= upper_rw_latch;
|
||||||
|
}
|
||||||
|
else if (latch_mode <= BTR_MODIFY_LEAF)
|
||||||
|
rw_latch= latch_mode;
|
||||||
|
|
||||||
|
dberr_t err;
|
||||||
|
auto block_savepoint= mtr->get_savepoint();
|
||||||
|
buf_block_t *block= buf_page_get_gen(page_id, zip_size, rw_latch, guess,
|
||||||
|
buf_mode, mtr, &err, false);
|
||||||
|
if (!block)
|
||||||
|
{
|
||||||
|
if (err == DB_DECRYPTION_FAILED)
|
||||||
|
btr_decryption_failed(*index);
|
||||||
|
func_exit:
|
||||||
|
if (UNIV_LIKELY_NULL(heap))
|
||||||
|
mem_heap_free(heap);
|
||||||
|
|
||||||
|
if (mbr_adj)
|
||||||
|
/* remember that we will need to adjust parent MBR */
|
||||||
|
cur->rtr_info->mbr_adj= true;
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
const page_t *page= buf_block_get_frame(block);
|
||||||
|
#ifdef UNIV_ZIP_DEBUG
|
||||||
|
if (rw_latch != RW_NO_LATCH) {
|
||||||
|
const page_zip_des_t *page_zip= buf_block_get_page_zip(block);
|
||||||
|
ut_a(!page_zip || page_zip_validate(page_zip, page, index));
|
||||||
|
}
|
||||||
|
#endif /* UNIV_ZIP_DEBUG */
|
||||||
|
|
||||||
|
ut_ad(fil_page_index_page_check(page));
|
||||||
|
ut_ad(index->id == btr_page_get_index_id(page));
|
||||||
|
|
||||||
|
if (height != ULINT_UNDEFINED);
|
||||||
|
else if (page_is_leaf(page) &&
|
||||||
|
rw_latch != RW_NO_LATCH && rw_latch != root_leaf_rw_latch)
|
||||||
|
{
|
||||||
|
/* The root page is also a leaf page (root_leaf).
|
||||||
|
We should reacquire the page, because the root page
|
||||||
|
is latched differently from leaf pages. */
|
||||||
|
ut_ad(root_leaf_rw_latch != RW_NO_LATCH);
|
||||||
|
ut_ad(rw_latch == RW_S_LATCH || rw_latch == RW_SX_LATCH);
|
||||||
|
|
||||||
|
ut_ad(block == mtr->at_savepoint(block_savepoint));
|
||||||
|
mtr->rollback_to_savepoint(block_savepoint);
|
||||||
|
|
||||||
|
upper_rw_latch= root_leaf_rw_latch;
|
||||||
|
goto search_loop;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* We are in the root node */
|
||||||
|
|
||||||
|
height= btr_page_get_level(page);
|
||||||
|
cur->tree_height= height + 1;
|
||||||
|
|
||||||
|
ut_ad(cur->rtr_info);
|
||||||
|
|
||||||
|
/* If SSN in memory is not initialized, fetch it from root page */
|
||||||
|
if (!rtr_get_current_ssn_id(index))
|
||||||
|
/* FIXME: do this in dict_load_table_one() */
|
||||||
|
index->set_ssn(page_get_ssn_id(page) + 1);
|
||||||
|
|
||||||
|
/* Save the MBR */
|
||||||
|
cur->rtr_info->thr= cur->thr;
|
||||||
|
rtr_get_mbr_from_tuple(tuple, &cur->rtr_info->mbr);
|
||||||
|
|
||||||
|
#ifdef BTR_CUR_ADAPT
|
||||||
|
info->root_guess= block;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
if (height == 0) {
|
||||||
|
if (rw_latch == RW_NO_LATCH)
|
||||||
|
{
|
||||||
|
ut_ad(block == mtr->at_savepoint(block_savepoint));
|
||||||
|
rtr_latch_leaves(block_savepoint, latch_mode, cur, mtr);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (latch_mode) {
|
||||||
|
case BTR_MODIFY_TREE:
|
||||||
|
case BTR_CONT_MODIFY_TREE:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (!latch_by_caller)
|
||||||
|
{
|
||||||
|
/* Release the tree s-latch */
|
||||||
|
mtr->rollback_to_savepoint(savepoint,
|
||||||
|
savepoint + 1);
|
||||||
|
block_savepoint--;
|
||||||
|
root_savepoint--;
|
||||||
|
}
|
||||||
|
/* release upper blocks */
|
||||||
|
if (savepoint < block_savepoint)
|
||||||
|
mtr->rollback_to_savepoint(savepoint, block_savepoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
page_mode= mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Remember the page search mode */
|
||||||
|
search_mode= page_mode;
|
||||||
|
|
||||||
|
/* Some adjustment on search mode, when the page search mode is
|
||||||
|
PAGE_CUR_RTREE_LOCATE or PAGE_CUR_RTREE_INSERT, as we are searching
|
||||||
|
with MBRs. When it is not the target level, we should search all
|
||||||
|
sub-trees that "CONTAIN" the search range/MBR. When it is at the
|
||||||
|
target level, the search becomes PAGE_CUR_LE */
|
||||||
|
|
||||||
|
if (page_mode == PAGE_CUR_RTREE_INSERT)
|
||||||
|
{
|
||||||
|
page_mode= (level == height)
|
||||||
|
? PAGE_CUR_LE
|
||||||
|
: PAGE_CUR_RTREE_INSERT;
|
||||||
|
|
||||||
|
ut_ad(!page_is_leaf(page) || page_mode == PAGE_CUR_LE);
|
||||||
|
}
|
||||||
|
else if (page_mode == PAGE_CUR_RTREE_LOCATE && level == height)
|
||||||
|
page_mode= level == 0 ? PAGE_CUR_LE : PAGE_CUR_RTREE_GET_FATHER;
|
||||||
|
|
||||||
|
up_match= 0;
|
||||||
|
low_match= 0;
|
||||||
|
|
||||||
|
if (latch_mode == BTR_MODIFY_TREE || latch_mode == BTR_CONT_MODIFY_TREE)
|
||||||
|
/* Tree are locked, no need for Page Lock to protect the "path" */
|
||||||
|
cur->rtr_info->need_page_lock= false;
|
||||||
|
|
||||||
|
cur->page_cur.block= block;
|
||||||
|
|
||||||
|
if (page_mode >= PAGE_CUR_CONTAIN)
|
||||||
|
{
|
||||||
|
found= rtr_cur_search_with_match(block, index, tuple, page_mode,
|
||||||
|
&cur->page_cur, cur->rtr_info);
|
||||||
|
|
||||||
|
/* Need to use BTR_MODIFY_TREE to do the MBR adjustment */
|
||||||
|
if (search_mode == PAGE_CUR_RTREE_INSERT && cur->rtr_info->mbr_adj) {
|
||||||
|
static_assert(BTR_MODIFY_TREE == (8 | BTR_MODIFY_LEAF), "");
|
||||||
|
|
||||||
|
if (!(latch_mode & 8))
|
||||||
|
/* Parent MBR needs updated, should retry with BTR_MODIFY_TREE */
|
||||||
|
goto func_exit;
|
||||||
|
|
||||||
|
cur->rtr_info->mbr_adj= false;
|
||||||
|
mbr_adj= true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (found && page_mode == PAGE_CUR_RTREE_GET_FATHER)
|
||||||
|
cur->low_match= DICT_INDEX_SPATIAL_NODEPTR_SIZE + 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Search for complete index fields. */
|
||||||
|
up_bytes= low_bytes= 0;
|
||||||
|
if (page_cur_search_with_match(tuple, page_mode, &up_match,
|
||||||
|
&low_match, &cur->page_cur, nullptr)) {
|
||||||
|
err= DB_CORRUPTION;
|
||||||
|
goto func_exit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If this is the desired level, leave the loop */
|
||||||
|
|
||||||
|
ut_ad(height == btr_page_get_level(btr_cur_get_page(cur)));
|
||||||
|
|
||||||
|
/* Add Predicate lock if it is serializable isolation
|
||||||
|
and only if it is in the search case */
|
||||||
|
if (mode >= PAGE_CUR_CONTAIN && mode != PAGE_CUR_RTREE_INSERT &&
|
||||||
|
mode != PAGE_CUR_RTREE_LOCATE && cur->rtr_info->need_prdt_lock)
|
||||||
|
{
|
||||||
|
lock_prdt_t prdt;
|
||||||
|
|
||||||
|
{
|
||||||
|
trx_t* trx= thr_get_trx(cur->thr);
|
||||||
|
TMLockTrxGuard g{TMLockTrxArgs(*trx)};
|
||||||
|
lock_init_prdt_from_mbr(&prdt, &cur->rtr_info->mbr, mode,
|
||||||
|
trx->lock.lock_heap);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rw_latch == RW_NO_LATCH && height != 0)
|
||||||
|
block->page.lock.s_lock();
|
||||||
|
|
||||||
|
lock_prdt_lock(block, &prdt, index, LOCK_S, LOCK_PREDICATE, cur->thr);
|
||||||
|
|
||||||
|
if (rw_latch == RW_NO_LATCH && height != 0)
|
||||||
|
block->page.lock.s_unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (level != height)
|
||||||
|
{
|
||||||
|
ut_ad(height > 0);
|
||||||
|
|
||||||
|
height--;
|
||||||
|
guess= nullptr;
|
||||||
|
|
||||||
|
const rec_t *node_ptr= btr_cur_get_rec(cur);
|
||||||
|
|
||||||
|
offsets= rec_get_offsets(node_ptr, index, offsets, 0,
|
||||||
|
ULINT_UNDEFINED, &heap);
|
||||||
|
|
||||||
|
if (page_rec_is_supremum(node_ptr))
|
||||||
|
{
|
||||||
|
cur->low_match= 0;
|
||||||
|
cur->up_match= 0;
|
||||||
|
goto func_exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we are doing insertion or record locating,
|
||||||
|
remember the tree nodes we visited */
|
||||||
|
if (page_mode == PAGE_CUR_RTREE_INSERT ||
|
||||||
|
(search_mode == PAGE_CUR_RTREE_LOCATE &&
|
||||||
|
latch_mode != BTR_MODIFY_LEAF))
|
||||||
|
{
|
||||||
|
const bool add_latch= latch_mode == BTR_MODIFY_TREE &&
|
||||||
|
rw_latch == RW_NO_LATCH;
|
||||||
|
|
||||||
|
if (add_latch)
|
||||||
|
{
|
||||||
|
ut_ad(mtr->memo_contains_flagged(&index->lock, MTR_MEMO_X_LOCK |
|
||||||
|
MTR_MEMO_SX_LOCK));
|
||||||
|
block->page.lock.s_lock();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Store the parent cursor location */
|
||||||
|
ut_d(auto num_stored=)
|
||||||
|
rtr_store_parent_path(block, cur, latch_mode, height + 1, mtr);
|
||||||
|
|
||||||
|
if (page_mode == PAGE_CUR_RTREE_INSERT)
|
||||||
|
{
|
||||||
|
btr_pcur_t *r_cursor= rtr_get_parent_cursor(cur, height + 1, true);
|
||||||
|
/* If it is insertion, there should be only one parent for
|
||||||
|
each level traverse */
|
||||||
|
ut_ad(num_stored == 1);
|
||||||
|
node_ptr= btr_pcur_get_rec(r_cursor);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (add_latch)
|
||||||
|
block->page.lock.s_unlock();
|
||||||
|
|
||||||
|
ut_ad(!page_rec_is_supremum(node_ptr));
|
||||||
|
}
|
||||||
|
|
||||||
|
ut_ad(page_mode == search_mode ||
|
||||||
|
(page_mode == PAGE_CUR_WITHIN &&
|
||||||
|
search_mode == PAGE_CUR_RTREE_LOCATE));
|
||||||
|
page_mode= search_mode;
|
||||||
|
|
||||||
|
if (height == level && latch_mode == BTR_MODIFY_TREE)
|
||||||
|
{
|
||||||
|
ut_ad(upper_rw_latch == RW_X_LATCH);
|
||||||
|
for (auto i= root_savepoint, n= mtr->get_savepoint(); i < n; i++)
|
||||||
|
mtr->upgrade_buffer_fix(i, RW_X_LATCH);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Go to the child node */
|
||||||
|
page_id.set_page_no(btr_node_ptr_get_child_page_no(node_ptr, offsets));
|
||||||
|
|
||||||
|
if (page_mode >= PAGE_CUR_CONTAIN && page_mode != PAGE_CUR_RTREE_INSERT)
|
||||||
|
{
|
||||||
|
rtr_node_path_t *path= cur->rtr_info->path;
|
||||||
|
|
||||||
|
if (found && !path->empty())
|
||||||
|
{
|
||||||
|
ut_ad(path->back().page_no == page_id.page_no());
|
||||||
|
path->pop_back();
|
||||||
|
#ifdef UNIV_DEBUG
|
||||||
|
if (page_mode == PAGE_CUR_RTREE_LOCATE &&
|
||||||
|
latch_mode != BTR_MODIFY_LEAF)
|
||||||
|
{
|
||||||
|
btr_pcur_t* pcur= cur->rtr_info->parent_path->back().cursor;
|
||||||
|
rec_t *my_node_ptr= btr_pcur_get_rec(pcur);
|
||||||
|
|
||||||
|
offsets= rec_get_offsets(my_node_ptr, index, offsets,
|
||||||
|
0, ULINT_UNDEFINED, &heap);
|
||||||
|
|
||||||
|
ut_ad(page_id.page_no() ==
|
||||||
|
btr_node_ptr_get_child_page_no(my_node_ptr, offsets));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
goto search_loop;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (level)
|
||||||
|
{
|
||||||
|
if (upper_rw_latch == RW_NO_LATCH)
|
||||||
|
{
|
||||||
|
ut_ad(latch_mode == BTR_CONT_MODIFY_TREE);
|
||||||
|
btr_block_get(*index, page_id.page_no(), RW_X_LATCH, false, mtr, &err);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ut_ad(mtr->memo_contains_flagged(block, upper_rw_latch));
|
||||||
|
ut_ad(!latch_by_caller);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (page_mode <= PAGE_CUR_LE)
|
||||||
|
{
|
||||||
|
cur->low_match= low_match;
|
||||||
|
cur->up_match= up_match;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cur->low_match= low_match;
|
||||||
|
cur->low_bytes= low_bytes;
|
||||||
|
cur->up_match= up_match;
|
||||||
|
cur->up_bytes= up_bytes;
|
||||||
|
|
||||||
|
ut_ad(up_match != ULINT_UNDEFINED || mode != PAGE_CUR_GE);
|
||||||
|
ut_ad(up_match != ULINT_UNDEFINED || mode != PAGE_CUR_LE);
|
||||||
|
ut_ad(low_match != ULINT_UNDEFINED || mode != PAGE_CUR_LE);
|
||||||
|
}
|
||||||
|
|
||||||
|
goto func_exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
dberr_t rtr_search_leaf(btr_cur_t *cur, const dtuple_t *tuple,
|
||||||
|
btr_latch_mode latch_mode,
|
||||||
|
mtr_t *mtr, page_cur_mode_t mode)
|
||||||
|
{
|
||||||
|
return rtr_search_to_nth_level(0, tuple, mode, latch_mode, cur, mtr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Search for a spatial index leaf page record.
|
||||||
|
@param pcur cursor
|
||||||
|
@param tuple search tuple
|
||||||
|
@param mode search mode
|
||||||
|
@param mtr mini-transaction */
|
||||||
|
dberr_t rtr_search_leaf(btr_pcur_t *pcur, const dtuple_t *tuple,
|
||||||
|
page_cur_mode_t mode, mtr_t *mtr)
|
||||||
|
{
|
||||||
|
#ifdef UNIV_DEBUG
|
||||||
|
switch (mode) {
|
||||||
|
case PAGE_CUR_CONTAIN:
|
||||||
|
case PAGE_CUR_INTERSECT:
|
||||||
|
case PAGE_CUR_WITHIN:
|
||||||
|
case PAGE_CUR_DISJOINT:
|
||||||
|
case PAGE_CUR_MBR_EQUAL:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ut_ad("invalid mode" == 0);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
pcur->latch_mode= BTR_SEARCH_LEAF;
|
||||||
|
pcur->search_mode= mode;
|
||||||
|
pcur->pos_state= BTR_PCUR_IS_POSITIONED;
|
||||||
|
pcur->trx_if_known= nullptr;
|
||||||
|
return rtr_search_leaf(&pcur->btr_cur, tuple, BTR_SEARCH_LEAF, mtr, mode);
|
||||||
|
}
|
||||||
|
|
||||||
/**************************************************************//**
|
/**************************************************************//**
|
||||||
Initializes and opens a persistent cursor to an index tree. It should be
|
Initializes and opens a persistent cursor to an index tree. It should be
|
||||||
closed with btr_pcur_close. Mainly called by row_search_index_entry() */
|
closed with btr_pcur_close. */
|
||||||
bool
|
bool rtr_search(
|
||||||
rtr_pcur_open(
|
|
||||||
dict_index_t* index, /*!< in: index */
|
|
||||||
const dtuple_t* tuple, /*!< in: tuple on which search done */
|
const dtuple_t* tuple, /*!< in: tuple on which search done */
|
||||||
btr_latch_mode latch_mode,/*!< in: BTR_SEARCH_LEAF, ... */
|
btr_latch_mode latch_mode,/*!< in: BTR_MODIFY_LEAF, ... */
|
||||||
btr_pcur_t* cursor, /*!< in: memory buffer for persistent cursor */
|
btr_pcur_t* cursor, /*!< in: memory buffer for persistent cursor */
|
||||||
mtr_t* mtr) /*!< in: mtr */
|
mtr_t* mtr) /*!< in: mtr */
|
||||||
{
|
{
|
||||||
static_assert(BTR_MODIFY_TREE == (8 | BTR_MODIFY_LEAF), "");
|
static_assert(BTR_MODIFY_TREE == (8 | BTR_MODIFY_LEAF), "");
|
||||||
ut_ad(latch_mode & BTR_MODIFY_LEAF);
|
ut_ad(latch_mode & BTR_MODIFY_LEAF);
|
||||||
|
ut_ad(!(latch_mode & BTR_ALREADY_S_LATCHED));
|
||||||
|
ut_ad(mtr->is_empty());
|
||||||
|
|
||||||
/* Initialize the cursor */
|
/* Initialize the cursor */
|
||||||
|
|
||||||
btr_pcur_init(cursor);
|
btr_pcur_init(cursor);
|
||||||
|
|
||||||
cursor->latch_mode = BTR_LATCH_MODE_WITHOUT_FLAGS(latch_mode);
|
cursor->latch_mode = BTR_LATCH_MODE_WITHOUT_FLAGS(latch_mode);
|
||||||
cursor->search_mode = PAGE_CUR_RTREE_LOCATE;
|
cursor->search_mode = PAGE_CUR_RTREE_LOCATE;
|
||||||
cursor->trx_if_known = NULL;
|
cursor->trx_if_known = nullptr;
|
||||||
|
|
||||||
|
if (latch_mode & 8) {
|
||||||
|
mtr_x_lock_index(cursor->index(), mtr);
|
||||||
|
} else {
|
||||||
|
latch_mode
|
||||||
|
= btr_latch_mode(latch_mode | BTR_ALREADY_S_LATCHED);
|
||||||
|
mtr_sx_lock_index(cursor->index(), mtr);
|
||||||
|
}
|
||||||
|
|
||||||
/* Search with the tree cursor */
|
/* Search with the tree cursor */
|
||||||
|
|
||||||
btr_cur_t* btr_cursor = btr_pcur_get_btr_cur(cursor);
|
btr_cur_t* btr_cursor = btr_pcur_get_btr_cur(cursor);
|
||||||
btr_cursor->page_cur.index = index;
|
|
||||||
|
|
||||||
btr_cursor->rtr_info = rtr_create_rtr_info(false, false,
|
btr_cursor->rtr_info
|
||||||
btr_cursor, index);
|
= rtr_create_rtr_info(false, false,
|
||||||
|
btr_cursor, cursor->index());
|
||||||
|
|
||||||
/* Purge will SX lock the tree instead of take Page Locks */
|
|
||||||
if (btr_cursor->thr) {
|
if (btr_cursor->thr) {
|
||||||
btr_cursor->rtr_info->need_page_lock = true;
|
btr_cursor->rtr_info->need_page_lock = true;
|
||||||
btr_cursor->rtr_info->thr = btr_cursor->thr;
|
btr_cursor->rtr_info->thr = btr_cursor->thr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((latch_mode & 8) && index->lock.have_u_not_x()) {
|
if (rtr_search_leaf(btr_cursor, tuple, latch_mode, mtr)
|
||||||
index->lock.u_x_upgrade(SRW_LOCK_CALL);
|
!= DB_SUCCESS) {
|
||||||
mtr->lock_upgrade(index->lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (btr_cur_search_to_nth_level(0, tuple, PAGE_CUR_RTREE_LOCATE,
|
|
||||||
latch_mode,
|
|
||||||
btr_cursor, mtr) != DB_SUCCESS) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -560,7 +1065,8 @@ rtr_pcur_open(
|
|||||||
|
|
||||||
const rec_t* rec = btr_pcur_get_rec(cursor);
|
const rec_t* rec = btr_pcur_get_rec(cursor);
|
||||||
|
|
||||||
const bool d= rec_get_deleted_flag(rec, index->table->not_redundant());
|
const bool d= rec_get_deleted_flag(
|
||||||
|
rec, cursor->index()->table->not_redundant());
|
||||||
|
|
||||||
if (page_rec_is_infimum(rec)
|
if (page_rec_is_infimum(rec)
|
||||||
|| btr_pcur_get_low_match(cursor) != dtuple_get_n_fields(tuple)
|
|| btr_pcur_get_low_match(cursor) != dtuple_get_n_fields(tuple)
|
||||||
@@ -571,26 +1077,12 @@ rtr_pcur_open(
|
|||||||
btr_cursor->rtr_info->fd_del = true;
|
btr_cursor->rtr_info->fd_del = true;
|
||||||
btr_cursor->low_match = 0;
|
btr_cursor->low_match = 0;
|
||||||
}
|
}
|
||||||
/* Did not find matched row in first dive. Release
|
|
||||||
latched block if any before search more pages */
|
|
||||||
if (!(latch_mode & 8)) {
|
|
||||||
ulint tree_idx = btr_cursor->tree_height - 1;
|
|
||||||
rtr_info_t* rtr_info = btr_cursor->rtr_info;
|
|
||||||
|
|
||||||
if (rtr_info->tree_blocks[tree_idx]) {
|
mtr->rollback_to_savepoint(1);
|
||||||
mtr_release_block_at_savepoint(
|
|
||||||
mtr,
|
|
||||||
rtr_info->tree_savepoints[tree_idx],
|
|
||||||
rtr_info->tree_blocks[tree_idx]);
|
|
||||||
rtr_info->tree_blocks[tree_idx] = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!rtr_pcur_getnext_from_path(tuple, PAGE_CUR_RTREE_LOCATE,
|
if (!rtr_pcur_getnext_from_path(tuple, PAGE_CUR_RTREE_LOCATE,
|
||||||
btr_cursor, 0, latch_mode,
|
btr_cursor, 0, latch_mode,
|
||||||
latch_mode
|
true, mtr)) {
|
||||||
& (8 | BTR_ALREADY_S_LATCHED),
|
|
||||||
mtr)) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -598,6 +1090,10 @@ rtr_pcur_open(
|
|||||||
== dtuple_get_n_fields(tuple));
|
== dtuple_get_n_fields(tuple));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!(latch_mode & 8)) {
|
||||||
|
mtr->rollback_to_savepoint(0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -641,8 +1137,7 @@ static const rec_t* rtr_get_father_node(
|
|||||||
if (sea_cur && sea_cur->tree_height > level) {
|
if (sea_cur && sea_cur->tree_height > level) {
|
||||||
ut_ad(mtr->memo_contains_flagged(&index->lock, MTR_MEMO_X_LOCK
|
ut_ad(mtr->memo_contains_flagged(&index->lock, MTR_MEMO_X_LOCK
|
||||||
| MTR_MEMO_SX_LOCK));
|
| MTR_MEMO_SX_LOCK));
|
||||||
if (rtr_cur_restore_position(BTR_CONT_MODIFY_TREE, sea_cur,
|
if (rtr_cur_restore_position(sea_cur, level, mtr)) {
|
||||||
level, mtr)) {
|
|
||||||
btr_pcur_t* r_cursor = rtr_get_parent_cursor(
|
btr_pcur_t* r_cursor = rtr_get_parent_cursor(
|
||||||
sea_cur, level, false);
|
sea_cur, level, false);
|
||||||
|
|
||||||
@@ -668,9 +1163,8 @@ static const rec_t* rtr_get_father_node(
|
|||||||
|
|
||||||
btr_cur->rtr_info = rtr_create_rtr_info(false, false, btr_cur, index);
|
btr_cur->rtr_info = rtr_create_rtr_info(false, false, btr_cur, index);
|
||||||
|
|
||||||
if (btr_cur_search_to_nth_level(level, tuple,
|
if (rtr_search_to_nth_level(level, tuple, PAGE_CUR_RTREE_LOCATE,
|
||||||
PAGE_CUR_RTREE_LOCATE,
|
BTR_CONT_MODIFY_TREE, btr_cur, mtr)
|
||||||
BTR_CONT_MODIFY_TREE, btr_cur, mtr)
|
|
||||||
!= DB_SUCCESS) {
|
!= DB_SUCCESS) {
|
||||||
} else if (sea_cur && sea_cur->tree_height == level) {
|
} else if (sea_cur && sea_cur->tree_height == level) {
|
||||||
rec = btr_cur_get_rec(btr_cur);
|
rec = btr_cur_get_rec(btr_cur);
|
||||||
@@ -729,9 +1223,8 @@ rtr_page_get_father_node_ptr(
|
|||||||
page_no = btr_cur_get_block(cursor)->page.id().page_no();
|
page_no = btr_cur_get_block(cursor)->page.id().page_no();
|
||||||
index = btr_cur_get_index(cursor);
|
index = btr_cur_get_index(cursor);
|
||||||
|
|
||||||
ut_ad(srv_read_only_mode
|
ut_ad(mtr->memo_contains_flagged(&index->lock, MTR_MEMO_X_LOCK
|
||||||
|| mtr->memo_contains_flagged(&index->lock, MTR_MEMO_X_LOCK
|
| MTR_MEMO_SX_LOCK));
|
||||||
| MTR_MEMO_SX_LOCK));
|
|
||||||
|
|
||||||
ut_ad(dict_index_get_page(index) != page_no);
|
ut_ad(dict_index_get_page(index) != page_no);
|
||||||
|
|
||||||
@@ -879,32 +1372,10 @@ rtr_init_rtr_info(
|
|||||||
|
|
||||||
if (!reinit) {
|
if (!reinit) {
|
||||||
/* Reset all members. */
|
/* Reset all members. */
|
||||||
rtr_info->path = NULL;
|
memset(rtr_info, 0, sizeof *rtr_info);
|
||||||
rtr_info->parent_path = NULL;
|
static_assert(PAGE_CUR_UNSUPP == 0, "compatibility");
|
||||||
rtr_info->matches = NULL;
|
|
||||||
|
|
||||||
mysql_mutex_init(rtr_path_mutex_key, &rtr_info->rtr_path_mutex,
|
mysql_mutex_init(rtr_path_mutex_key, &rtr_info->rtr_path_mutex,
|
||||||
nullptr);
|
nullptr);
|
||||||
|
|
||||||
memset(rtr_info->tree_blocks, 0x0,
|
|
||||||
sizeof(rtr_info->tree_blocks));
|
|
||||||
memset(rtr_info->tree_savepoints, 0x0,
|
|
||||||
sizeof(rtr_info->tree_savepoints));
|
|
||||||
rtr_info->mbr.xmin = 0.0;
|
|
||||||
rtr_info->mbr.xmax = 0.0;
|
|
||||||
rtr_info->mbr.ymin = 0.0;
|
|
||||||
rtr_info->mbr.ymax = 0.0;
|
|
||||||
rtr_info->thr = NULL;
|
|
||||||
rtr_info->heap = NULL;
|
|
||||||
rtr_info->cursor = NULL;
|
|
||||||
rtr_info->index = NULL;
|
|
||||||
rtr_info->need_prdt_lock = false;
|
|
||||||
rtr_info->need_page_lock = false;
|
|
||||||
rtr_info->allocated = false;
|
|
||||||
rtr_info->mbr_adj = false;
|
|
||||||
rtr_info->fd_del = false;
|
|
||||||
rtr_info->search_tuple = NULL;
|
|
||||||
rtr_info->search_mode = PAGE_CUR_UNSUPP;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ut_ad(!rtr_info->matches || rtr_info->matches->matched_recs->empty());
|
ut_ad(!rtr_info->matches || rtr_info->matches->matched_recs->empty());
|
||||||
@@ -1130,7 +1601,6 @@ struct optimistic_get
|
|||||||
static
|
static
|
||||||
bool
|
bool
|
||||||
rtr_cur_restore_position(
|
rtr_cur_restore_position(
|
||||||
ulint latch_mode, /*!< in: BTR_SEARCH_LEAF, ... */
|
|
||||||
btr_cur_t* btr_cur, /*!< in: detached persistent cursor */
|
btr_cur_t* btr_cur, /*!< in: detached persistent cursor */
|
||||||
ulint level, /*!< in: index level */
|
ulint level, /*!< in: index level */
|
||||||
mtr_t* mtr) /*!< in: mtr */
|
mtr_t* mtr) /*!< in: mtr */
|
||||||
@@ -1158,8 +1628,6 @@ rtr_cur_restore_position(
|
|||||||
r_cursor->modify_clock = 100;
|
r_cursor->modify_clock = 100;
|
||||||
);
|
);
|
||||||
|
|
||||||
ut_ad(latch_mode == BTR_CONT_MODIFY_TREE);
|
|
||||||
|
|
||||||
if (r_cursor->block_when_stored.run_with_hint(
|
if (r_cursor->block_when_stored.run_with_hint(
|
||||||
optimistic_get(r_cursor, mtr))) {
|
optimistic_get(r_cursor, mtr))) {
|
||||||
ut_ad(r_cursor->pos_state == BTR_PCUR_IS_POSITIONED);
|
ut_ad(r_cursor->pos_state == BTR_PCUR_IS_POSITIONED);
|
||||||
|
@@ -1525,8 +1525,7 @@ static void innodb_drop_database(handlerton*, char *path)
|
|||||||
mtr_t mtr;
|
mtr_t mtr;
|
||||||
mtr.start();
|
mtr.start();
|
||||||
pcur.btr_cur.page_cur.index = sys_index;
|
pcur.btr_cur.page_cur.index = sys_index;
|
||||||
err= btr_pcur_open_on_user_rec(&tuple, PAGE_CUR_GE,
|
err= btr_pcur_open_on_user_rec(&tuple, BTR_SEARCH_LEAF, &pcur, &mtr);
|
||||||
BTR_SEARCH_LEAF, &pcur, &mtr);
|
|
||||||
if (err != DB_SUCCESS)
|
if (err != DB_SUCCESS)
|
||||||
goto err_exit;
|
goto err_exit;
|
||||||
|
|
||||||
@@ -7959,6 +7958,7 @@ report_error:
|
|||||||
|
|
||||||
#ifdef WITH_WSREP
|
#ifdef WITH_WSREP
|
||||||
if (!error_result && trx->is_wsrep()
|
if (!error_result && trx->is_wsrep()
|
||||||
|
&& !trx->is_bulk_insert()
|
||||||
&& wsrep_thd_is_local(m_user_thd)
|
&& wsrep_thd_is_local(m_user_thd)
|
||||||
&& !wsrep_thd_ignore_table(m_user_thd)
|
&& !wsrep_thd_ignore_table(m_user_thd)
|
||||||
&& !wsrep_consistency_check(m_user_thd)
|
&& !wsrep_consistency_check(m_user_thd)
|
||||||
@@ -10048,6 +10048,8 @@ wsrep_append_key(
|
|||||||
(shared, exclusive, semi...) */
|
(shared, exclusive, semi...) */
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
ut_ad(!trx->is_bulk_insert());
|
||||||
|
|
||||||
DBUG_ENTER("wsrep_append_key");
|
DBUG_ENTER("wsrep_append_key");
|
||||||
DBUG_PRINT("enter",
|
DBUG_PRINT("enter",
|
||||||
("thd: %lu trx: %lld", thd_get_thread_id(thd),
|
("thd: %lu trx: %lld", thd_get_thread_id(thd),
|
||||||
|
@@ -6097,7 +6097,8 @@ func_exit:
|
|||||||
|
|
||||||
que_thr_t* thr = pars_complete_graph_for_exec(
|
que_thr_t* thr = pars_complete_graph_for_exec(
|
||||||
NULL, trx, ctx->heap, NULL);
|
NULL, trx, ctx->heap, NULL);
|
||||||
const bool is_root = block->page.id().page_no() == index->page;
|
page_id_t id{block->page.id()};
|
||||||
|
const bool is_root = id.page_no() == index->page;
|
||||||
|
|
||||||
if (rec_is_metadata(rec, *index)) {
|
if (rec_is_metadata(rec, *index)) {
|
||||||
ut_ad(page_rec_is_user_rec(rec));
|
ut_ad(page_rec_is_user_rec(rec));
|
||||||
@@ -6114,8 +6115,10 @@ func_exit:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Ensure that the root page is in the correct format. */
|
/* Ensure that the root page is in the correct format. */
|
||||||
buf_block_t* root = btr_root_block_get(index, RW_X_LATCH,
|
id.set_page_no(index->page);
|
||||||
&mtr, &err);
|
buf_block_t* root = mtr.get_already_latched(
|
||||||
|
id, MTR_MEMO_PAGE_SX_FIX);
|
||||||
|
|
||||||
if (UNIV_UNLIKELY(!root)) {
|
if (UNIV_UNLIKELY(!root)) {
|
||||||
goto func_exit;
|
goto func_exit;
|
||||||
}
|
}
|
||||||
@@ -11293,7 +11296,8 @@ err_index:
|
|||||||
}
|
}
|
||||||
|
|
||||||
DBUG_EXECUTE_IF("stats_lock_fail",
|
DBUG_EXECUTE_IF("stats_lock_fail",
|
||||||
error = DB_LOCK_WAIT_TIMEOUT;);
|
error = DB_LOCK_WAIT_TIMEOUT;
|
||||||
|
trx_rollback_for_mysql(trx););
|
||||||
|
|
||||||
if (error == DB_SUCCESS) {
|
if (error == DB_SUCCESS) {
|
||||||
error = lock_sys_tables(trx);
|
error = lock_sys_tables(trx);
|
||||||
@@ -11311,6 +11315,18 @@ err_index:
|
|||||||
if (fts_exist) {
|
if (fts_exist) {
|
||||||
purge_sys.resume_FTS();
|
purge_sys.resume_FTS();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (trx->state == TRX_STATE_NOT_STARTED) {
|
||||||
|
/* Transaction may have been rolled back
|
||||||
|
due to a lock wait timeout, deadlock,
|
||||||
|
or a KILL statement. So restart the
|
||||||
|
transaction to remove the newly created
|
||||||
|
table or index stubs from data dictionary
|
||||||
|
and table cache in
|
||||||
|
rollback_inplace_alter_table() */
|
||||||
|
trx_start_for_ddl(trx);
|
||||||
|
}
|
||||||
|
|
||||||
DBUG_RETURN(true);
|
DBUG_RETURN(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
|
|
||||||
Copyright (c) 1997, 2016, Oracle and/or its affiliates. All Rights Reserved.
|
Copyright (c) 1997, 2016, Oracle and/or its affiliates. All Rights Reserved.
|
||||||
Copyright (c) 2016, 2022, MariaDB Corporation.
|
Copyright (c) 2016, 2023, MariaDB Corporation.
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify it under
|
This program is free software; you can redistribute it and/or modify it under
|
||||||
the terms of the GNU General Public License as published by the Free Software
|
the terms of the GNU General Public License as published by the Free Software
|
||||||
@@ -2299,7 +2299,7 @@ loop:
|
|||||||
btr_pcur_t pcur;
|
btr_pcur_t pcur;
|
||||||
pcur.btr_cur.page_cur.index= ibuf.index;
|
pcur.btr_cur.page_cur.index= ibuf.index;
|
||||||
ibuf_mtr_start(&mtr);
|
ibuf_mtr_start(&mtr);
|
||||||
if (btr_pcur_open(&tuple, PAGE_CUR_GE, BTR_MODIFY_LEAF, &pcur, 0, &mtr))
|
if (btr_pcur_open(&tuple, PAGE_CUR_GE, BTR_MODIFY_LEAF, &pcur, &mtr))
|
||||||
goto func_exit;
|
goto func_exit;
|
||||||
if (!btr_pcur_is_on_user_rec(&pcur))
|
if (!btr_pcur_is_on_user_rec(&pcur))
|
||||||
{
|
{
|
||||||
@@ -2495,8 +2495,8 @@ ibuf_merge_space(
|
|||||||
/* Position the cursor on the first matching record. */
|
/* Position the cursor on the first matching record. */
|
||||||
|
|
||||||
pcur.btr_cur.page_cur.index = ibuf.index;
|
pcur.btr_cur.page_cur.index = ibuf.index;
|
||||||
dberr_t err = btr_pcur_open(&tuple, PAGE_CUR_GE,
|
dberr_t err = btr_pcur_open(&tuple, PAGE_CUR_GE, BTR_SEARCH_LEAF,
|
||||||
BTR_SEARCH_LEAF, &pcur, 0, &mtr);
|
&pcur, &mtr);
|
||||||
ut_ad(err != DB_SUCCESS || page_validate(btr_pcur_get_page(&pcur),
|
ut_ad(err != DB_SUCCESS || page_validate(btr_pcur_get_page(&pcur),
|
||||||
ibuf.index));
|
ibuf.index));
|
||||||
|
|
||||||
@@ -3240,7 +3240,7 @@ ibuf_insert_low(
|
|||||||
ibuf_mtr_start(&mtr);
|
ibuf_mtr_start(&mtr);
|
||||||
pcur.btr_cur.page_cur.index = ibuf.index;
|
pcur.btr_cur.page_cur.index = ibuf.index;
|
||||||
|
|
||||||
err = btr_pcur_open(ibuf_entry, PAGE_CUR_LE, mode, &pcur, 0, &mtr);
|
err = btr_pcur_open(ibuf_entry, PAGE_CUR_LE, mode, &pcur, &mtr);
|
||||||
if (err != DB_SUCCESS) {
|
if (err != DB_SUCCESS) {
|
||||||
func_exit:
|
func_exit:
|
||||||
ibuf_mtr_commit(&mtr);
|
ibuf_mtr_commit(&mtr);
|
||||||
@@ -3957,8 +3957,6 @@ ibuf_restore_pos(
|
|||||||
position is to be restored */
|
position is to be restored */
|
||||||
mtr_t* mtr) /*!< in/out: mini-transaction */
|
mtr_t* mtr) /*!< in/out: mini-transaction */
|
||||||
{
|
{
|
||||||
ut_ad(mode == BTR_MODIFY_LEAF || mode == BTR_PURGE_TREE);
|
|
||||||
|
|
||||||
if (UNIV_LIKELY(pcur->restore_position(mode, mtr) ==
|
if (UNIV_LIKELY(pcur->restore_position(mode, mtr) ==
|
||||||
btr_pcur_t::SAME_ALL)) {
|
btr_pcur_t::SAME_ALL)) {
|
||||||
return true;
|
return true;
|
||||||
@@ -4039,12 +4037,11 @@ bool ibuf_delete_rec(const page_id_t page_id, btr_pcur_t* pcur,
|
|||||||
|
|
||||||
ibuf_mtr_start(mtr);
|
ibuf_mtr_start(mtr);
|
||||||
mysql_mutex_lock(&ibuf_mutex);
|
mysql_mutex_lock(&ibuf_mutex);
|
||||||
|
mtr_x_lock_index(ibuf.index, mtr);
|
||||||
|
|
||||||
if (!ibuf_restore_pos(page_id, search_tuple, BTR_PURGE_TREE,
|
if (!ibuf_restore_pos(page_id, search_tuple,
|
||||||
pcur, mtr)) {
|
BTR_PURGE_TREE_ALREADY_LATCHED, pcur, mtr)) {
|
||||||
|
|
||||||
mysql_mutex_unlock(&ibuf_mutex);
|
mysql_mutex_unlock(&ibuf_mutex);
|
||||||
ut_ad(mtr->has_committed());
|
|
||||||
goto func_exit;
|
goto func_exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4055,13 +4052,10 @@ bool ibuf_delete_rec(const page_id_t page_id, btr_pcur_t* pcur,
|
|||||||
ut_a(err == DB_SUCCESS);
|
ut_a(err == DB_SUCCESS);
|
||||||
|
|
||||||
ibuf_size_update(ibuf_root->page.frame);
|
ibuf_size_update(ibuf_root->page.frame);
|
||||||
mysql_mutex_unlock(&ibuf_mutex);
|
|
||||||
|
|
||||||
ibuf.empty = page_is_empty(ibuf_root->page.frame);
|
ibuf.empty = page_is_empty(ibuf_root->page.frame);
|
||||||
} else {
|
|
||||||
mysql_mutex_unlock(&ibuf_mutex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mysql_mutex_unlock(&ibuf_mutex);
|
||||||
ibuf_btr_pcur_commit_specify_mtr(pcur, mtr);
|
ibuf_btr_pcur_commit_specify_mtr(pcur, mtr);
|
||||||
|
|
||||||
func_exit:
|
func_exit:
|
||||||
@@ -4239,7 +4233,7 @@ loop:
|
|||||||
|
|
||||||
/* Position pcur in the insert buffer at the first entry for this
|
/* Position pcur in the insert buffer at the first entry for this
|
||||||
index page */
|
index page */
|
||||||
if (btr_pcur_open_on_user_rec(search_tuple, PAGE_CUR_GE,
|
if (btr_pcur_open_on_user_rec(search_tuple,
|
||||||
BTR_MODIFY_LEAF, &pcur, &mtr)
|
BTR_MODIFY_LEAF, &pcur, &mtr)
|
||||||
!= DB_SUCCESS) {
|
!= DB_SUCCESS) {
|
||||||
err = DB_CORRUPTION;
|
err = DB_CORRUPTION;
|
||||||
@@ -4456,7 +4450,7 @@ loop:
|
|||||||
|
|
||||||
/* Position pcur in the insert buffer at the first entry for the
|
/* Position pcur in the insert buffer at the first entry for the
|
||||||
space */
|
space */
|
||||||
if (btr_pcur_open_on_user_rec(&search_tuple, PAGE_CUR_GE,
|
if (btr_pcur_open_on_user_rec(&search_tuple,
|
||||||
BTR_MODIFY_LEAF, &pcur, &mtr)
|
BTR_MODIFY_LEAF, &pcur, &mtr)
|
||||||
!= DB_SUCCESS) {
|
!= DB_SUCCESS) {
|
||||||
goto leave_loop;
|
goto leave_loop;
|
||||||
|
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
Copyright (c) 1994, 2016, Oracle and/or its affiliates. All Rights Reserved.
|
Copyright (c) 1994, 2016, Oracle and/or its affiliates. All Rights Reserved.
|
||||||
Copyright (c) 2012, Facebook Inc.
|
Copyright (c) 2012, Facebook Inc.
|
||||||
Copyright (c) 2014, 2022, MariaDB Corporation.
|
Copyright (c) 2014, 2023, MariaDB Corporation.
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify it under
|
This program is free software; you can redistribute it and/or modify it under
|
||||||
the terms of the GNU General Public License as published by the Free Software
|
the terms of the GNU General Public License as published by the Free Software
|
||||||
@@ -211,13 +211,12 @@ btr_write_autoinc(dict_index_t* index, ib_uint64_t autoinc, bool reset = false)
|
|||||||
@param[in,out] mtr mini-transaction */
|
@param[in,out] mtr mini-transaction */
|
||||||
void btr_set_instant(buf_block_t* root, const dict_index_t& index, mtr_t* mtr);
|
void btr_set_instant(buf_block_t* root, const dict_index_t& index, mtr_t* mtr);
|
||||||
|
|
||||||
ATTRIBUTE_COLD __attribute__((nonnull, warn_unused_result))
|
ATTRIBUTE_COLD __attribute__((nonnull))
|
||||||
/** Reset the table to the canonical format on ROLLBACK of instant ALTER TABLE.
|
/** Reset the table to the canonical format on ROLLBACK of instant ALTER TABLE.
|
||||||
@param[in] index clustered index with instant ALTER TABLE
|
@param[in] index clustered index with instant ALTER TABLE
|
||||||
@param[in] all whether to reset FIL_PAGE_TYPE as well
|
@param[in] all whether to reset FIL_PAGE_TYPE as well
|
||||||
@param[in,out] mtr mini-transaction
|
@param[in,out] mtr mini-transaction */
|
||||||
@return error code */
|
void btr_reset_instant(const dict_index_t &index, bool all, mtr_t *mtr);
|
||||||
dberr_t btr_reset_instant(const dict_index_t &index, bool all, mtr_t *mtr);
|
|
||||||
|
|
||||||
/*************************************************************//**
|
/*************************************************************//**
|
||||||
Makes tree one level higher by splitting the root, and inserts
|
Makes tree one level higher by splitting the root, and inserts
|
||||||
@@ -241,7 +240,7 @@ btr_root_raise_and_insert(
|
|||||||
ulint n_ext, /*!< in: number of externally stored columns */
|
ulint n_ext, /*!< in: number of externally stored columns */
|
||||||
mtr_t* mtr, /*!< in: mtr */
|
mtr_t* mtr, /*!< in: mtr */
|
||||||
dberr_t* err) /*!< out: error code */
|
dberr_t* err) /*!< out: error code */
|
||||||
MY_ATTRIBUTE((warn_unused_result));
|
MY_ATTRIBUTE((nonnull, warn_unused_result));
|
||||||
/*************************************************************//**
|
/*************************************************************//**
|
||||||
Reorganizes an index page.
|
Reorganizes an index page.
|
||||||
|
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
|
|
||||||
Copyright (c) 1994, 2019, Oracle and/or its affiliates. All Rights Reserved.
|
Copyright (c) 1994, 2019, Oracle and/or its affiliates. All Rights Reserved.
|
||||||
Copyright (c) 2017, 2022, MariaDB Corporation.
|
Copyright (c) 2017, 2023, MariaDB Corporation.
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify it under
|
This program is free software; you can redistribute it and/or modify it under
|
||||||
the terms of the GNU General Public License as published by the Free Software
|
the terms of the GNU General Public License as published by the Free Software
|
||||||
@@ -63,12 +63,6 @@ enum {
|
|||||||
BTR_KEEP_IBUF_BITMAP = 32
|
BTR_KEEP_IBUF_BITMAP = 32
|
||||||
};
|
};
|
||||||
|
|
||||||
/* btr_cur_latch_leaves() returns latched blocks and savepoints. */
|
|
||||||
struct btr_latch_leaves_t {
|
|
||||||
buf_block_t* blocks[3];
|
|
||||||
ulint savepoints[3];
|
|
||||||
};
|
|
||||||
|
|
||||||
#include "que0types.h"
|
#include "que0types.h"
|
||||||
#include "row0types.h"
|
#include "row0types.h"
|
||||||
|
|
||||||
@@ -126,51 +120,28 @@ bool
|
|||||||
btr_cur_instant_root_init(dict_index_t* index, const page_t* page)
|
btr_cur_instant_root_init(dict_index_t* index, const page_t* page)
|
||||||
ATTRIBUTE_COLD __attribute__((nonnull, warn_unused_result));
|
ATTRIBUTE_COLD __attribute__((nonnull, warn_unused_result));
|
||||||
|
|
||||||
/** Optimistically latches the leaf page or pages requested.
|
|
||||||
@param[in] block guessed buffer block
|
|
||||||
@param[in] modify_clock modify clock value
|
|
||||||
@param[in,out] latch_mode BTR_SEARCH_LEAF, ...
|
|
||||||
@param[in,out] cursor cursor
|
|
||||||
@param[in] mtr mini-transaction
|
|
||||||
@return true if success */
|
|
||||||
bool
|
|
||||||
btr_cur_optimistic_latch_leaves(
|
|
||||||
buf_block_t* block,
|
|
||||||
ib_uint64_t modify_clock,
|
|
||||||
btr_latch_mode* latch_mode,
|
|
||||||
btr_cur_t* cursor,
|
|
||||||
mtr_t* mtr);
|
|
||||||
|
|
||||||
MY_ATTRIBUTE((warn_unused_result))
|
MY_ATTRIBUTE((warn_unused_result))
|
||||||
/** Searches an index tree and positions a tree cursor on a given level.
|
/********************************************************************//**
|
||||||
|
Searches an index tree and positions a tree cursor on a given non-leaf level.
|
||||||
NOTE: n_fields_cmp in tuple must be set so that it cannot be compared
|
NOTE: n_fields_cmp in tuple must be set so that it cannot be compared
|
||||||
to node pointer page number fields on the upper levels of the tree!
|
to node pointer page number fields on the upper levels of the tree!
|
||||||
Note that if mode is PAGE_CUR_LE, which is used in inserts, then
|
|
||||||
cursor->up_match and cursor->low_match both will have sensible values.
|
cursor->up_match and cursor->low_match both will have sensible values.
|
||||||
If mode is PAGE_CUR_GE, then up_match will a have a sensible value.
|
Cursor is left at the place where an insert of the
|
||||||
|
search tuple should be performed in the B-tree. InnoDB does an insert
|
||||||
|
immediately after the cursor. Thus, the cursor may end up on a user record,
|
||||||
|
or on a page infimum record.
|
||||||
@param level the tree level of search
|
@param level the tree level of search
|
||||||
@param tuple data tuple; NOTE: n_fields_cmp in tuple must be set so that
|
@param tuple data tuple; NOTE: n_fields_cmp in tuple must be set so that
|
||||||
it cannot get compared to the node ptr page number field!
|
it cannot get compared to the node ptr page number field!
|
||||||
@param mode PAGE_CUR_L, ...; NOTE that if the search is made using a
|
@param latch RW_S_LATCH or RW_X_LATCH
|
||||||
unique prefix of a record, mode should be PAGE_CUR_LE, not
|
|
||||||
PAGE_CUR_GE, as the latter may end up on the previous page of
|
|
||||||
the record! Inserts should always be made using PAGE_CUR_LE
|
|
||||||
to search the position!
|
|
||||||
@param latch_mode BTR_SEARCH_LEAF, ..., ORed with at most one of BTR_INSERT,
|
|
||||||
BTR_DELETE_MARK, or BTR_DELETE;
|
|
||||||
cursor->left_block is used to store a pointer to the left
|
|
||||||
neighbor page
|
|
||||||
@param cursor tree cursor; the cursor page is s- or x-latched, but see also
|
@param cursor tree cursor; the cursor page is s- or x-latched, but see also
|
||||||
above!
|
above!
|
||||||
@param mtr mini-transaction
|
@param mtr mini-transaction
|
||||||
@param autoinc PAGE_ROOT_AUTO_INC to be written (0 if none)
|
|
||||||
@return DB_SUCCESS on success or error code otherwise */
|
@return DB_SUCCESS on success or error code otherwise */
|
||||||
dberr_t btr_cur_search_to_nth_level(ulint level,
|
dberr_t btr_cur_search_to_nth_level(ulint level,
|
||||||
const dtuple_t *tuple,
|
const dtuple_t *tuple,
|
||||||
page_cur_mode_t mode,
|
rw_lock_type_t rw_latch,
|
||||||
btr_latch_mode latch_mode,
|
btr_cur_t *cursor, mtr_t *mtr);
|
||||||
btr_cur_t *cursor, mtr_t *mtr,
|
|
||||||
ib_uint64_t autoinc= 0);
|
|
||||||
|
|
||||||
/*************************************************************//**
|
/*************************************************************//**
|
||||||
Tries to perform an insert to a page in an index tree, next to cursor.
|
Tries to perform an insert to a page in an index tree, next to cursor.
|
||||||
@@ -653,20 +624,6 @@ btr_rec_copy_externally_stored_field(
|
|||||||
ulint* len,
|
ulint* len,
|
||||||
mem_heap_t* heap);
|
mem_heap_t* heap);
|
||||||
|
|
||||||
/** Latches the leaf page or pages requested.
|
|
||||||
@param[in] block leaf page where the search converged
|
|
||||||
@param[in] latch_mode BTR_SEARCH_LEAF, ...
|
|
||||||
@param[in] cursor cursor
|
|
||||||
@param[in,out] mtr mini-transaction
|
|
||||||
@param[out] latch_leaves latched blocks and savepoints */
|
|
||||||
void
|
|
||||||
btr_cur_latch_leaves(
|
|
||||||
buf_block_t* block,
|
|
||||||
btr_latch_mode latch_mode,
|
|
||||||
btr_cur_t* cursor,
|
|
||||||
mtr_t* mtr,
|
|
||||||
btr_latch_leaves_t* latch_leaves = nullptr);
|
|
||||||
|
|
||||||
/*######################################################################*/
|
/*######################################################################*/
|
||||||
|
|
||||||
/** In the pessimistic delete, if the page data size drops below this
|
/** In the pessimistic delete, if the page data size drops below this
|
||||||
@@ -727,21 +684,16 @@ to know struct size! */
|
|||||||
struct btr_cur_t {
|
struct btr_cur_t {
|
||||||
page_cur_t page_cur; /*!< page cursor */
|
page_cur_t page_cur; /*!< page cursor */
|
||||||
purge_node_t* purge_node; /*!< purge node, for BTR_DELETE */
|
purge_node_t* purge_node; /*!< purge node, for BTR_DELETE */
|
||||||
buf_block_t* left_block; /*!< this field is used to store
|
|
||||||
a pointer to the left neighbor
|
|
||||||
page, in the cases
|
|
||||||
BTR_SEARCH_PREV and
|
|
||||||
BTR_MODIFY_PREV */
|
|
||||||
/*------------------------------*/
|
/*------------------------------*/
|
||||||
que_thr_t* thr; /*!< this field is only used
|
que_thr_t* thr; /*!< this field is only used
|
||||||
when btr_cur_search_to_nth_level
|
when search_leaf()
|
||||||
is called for an index entry
|
is called for an index entry
|
||||||
insertion: the calling query
|
insertion: the calling query
|
||||||
thread is passed here to be
|
thread is passed here to be
|
||||||
used in the insert buffer */
|
used in the insert buffer */
|
||||||
/*------------------------------*/
|
/*------------------------------*/
|
||||||
/** The following fields are used in
|
/** The following fields are used in
|
||||||
btr_cur_search_to_nth_level to pass information: */
|
search_leaf() to pass information: */
|
||||||
/* @{ */
|
/* @{ */
|
||||||
enum btr_cur_method flag; /*!< Search method used */
|
enum btr_cur_method flag; /*!< Search method used */
|
||||||
ulint tree_height; /*!< Tree height if the search is done
|
ulint tree_height; /*!< Tree height if the search is done
|
||||||
@@ -750,8 +702,7 @@ struct btr_cur_t {
|
|||||||
ulint up_match; /*!< If the search mode was PAGE_CUR_LE,
|
ulint up_match; /*!< If the search mode was PAGE_CUR_LE,
|
||||||
the number of matched fields to the
|
the number of matched fields to the
|
||||||
the first user record to the right of
|
the first user record to the right of
|
||||||
the cursor record after
|
the cursor record after search_leaf();
|
||||||
btr_cur_search_to_nth_level;
|
|
||||||
for the mode PAGE_CUR_GE, the matched
|
for the mode PAGE_CUR_GE, the matched
|
||||||
fields to the first user record AT THE
|
fields to the first user record AT THE
|
||||||
CURSOR or to the right of it;
|
CURSOR or to the right of it;
|
||||||
@@ -768,8 +719,7 @@ struct btr_cur_t {
|
|||||||
ulint low_match; /*!< if search mode was PAGE_CUR_LE,
|
ulint low_match; /*!< if search mode was PAGE_CUR_LE,
|
||||||
the number of matched fields to the
|
the number of matched fields to the
|
||||||
first user record AT THE CURSOR or
|
first user record AT THE CURSOR or
|
||||||
to the left of it after
|
to the left of it after search_leaf();
|
||||||
btr_cur_search_to_nth_level;
|
|
||||||
NOT defined for PAGE_CUR_GE or any
|
NOT defined for PAGE_CUR_GE or any
|
||||||
other search modes; see also the NOTE
|
other search modes; see also the NOTE
|
||||||
in up_match! */
|
in up_match! */
|
||||||
@@ -803,6 +753,24 @@ struct btr_cur_t {
|
|||||||
dberr_t open_leaf(bool first, dict_index_t *index, btr_latch_mode latch_mode,
|
dberr_t open_leaf(bool first, dict_index_t *index, btr_latch_mode latch_mode,
|
||||||
mtr_t *mtr);
|
mtr_t *mtr);
|
||||||
|
|
||||||
|
/** Search the leaf page record corresponding to a key.
|
||||||
|
@param tuple key to search for, with correct n_fields_cmp
|
||||||
|
@param mode search mode; PAGE_CUR_LE for unique prefix or for inserting
|
||||||
|
@param latch_mode latch mode
|
||||||
|
@param mtr mini-transaction
|
||||||
|
@return error code */
|
||||||
|
dberr_t search_leaf(const dtuple_t *tuple, page_cur_mode_t mode,
|
||||||
|
btr_latch_mode latch_mode, mtr_t *mtr);
|
||||||
|
|
||||||
|
/** Search the leaf page record corresponding to a key, exclusively latching
|
||||||
|
all sibling pages on the way.
|
||||||
|
@param tuple key to search for, with correct n_fields_cmp
|
||||||
|
@param mode search mode; PAGE_CUR_LE for unique prefix or for inserting
|
||||||
|
@param mtr mini-transaction
|
||||||
|
@return error code */
|
||||||
|
dberr_t pessimistic_search_leaf(const dtuple_t *tuple, page_cur_mode_t mode,
|
||||||
|
mtr_t *mtr);
|
||||||
|
|
||||||
/** Open the cursor at a random leaf page record.
|
/** Open the cursor at a random leaf page record.
|
||||||
@param offsets temporary memory for rec_get_offsets()
|
@param offsets temporary memory for rec_get_offsets()
|
||||||
@param heap memory heap for rec_get_offsets()
|
@param heap memory heap for rec_get_offsets()
|
||||||
@@ -862,14 +830,14 @@ inherited external field. */
|
|||||||
#define BTR_EXTERN_INHERITED_FLAG 64U
|
#define BTR_EXTERN_INHERITED_FLAG 64U
|
||||||
|
|
||||||
#ifdef BTR_CUR_HASH_ADAPT
|
#ifdef BTR_CUR_HASH_ADAPT
|
||||||
/** Number of searches down the B-tree in btr_cur_search_to_nth_level(). */
|
/** Number of searches down the B-tree in btr_cur_t::search_leaf(). */
|
||||||
extern ib_counter_t<ulint, ib_counter_element_t> btr_cur_n_non_sea;
|
extern ib_counter_t<ulint, ib_counter_element_t> btr_cur_n_non_sea;
|
||||||
/** Old value of btr_cur_n_non_sea. Copied by
|
/** Old value of btr_cur_n_non_sea. Copied by
|
||||||
srv_refresh_innodb_monitor_stats(). Referenced by
|
srv_refresh_innodb_monitor_stats(). Referenced by
|
||||||
srv_printf_innodb_monitor(). */
|
srv_printf_innodb_monitor(). */
|
||||||
extern ulint btr_cur_n_non_sea_old;
|
extern ulint btr_cur_n_non_sea_old;
|
||||||
/** Number of successful adaptive hash index lookups in
|
/** Number of successful adaptive hash index lookups in
|
||||||
btr_cur_search_to_nth_level(). */
|
btr_cur_t::search_leaf(). */
|
||||||
extern ib_counter_t<ulint, ib_counter_element_t> btr_cur_n_sea;
|
extern ib_counter_t<ulint, ib_counter_element_t> btr_cur_n_sea;
|
||||||
/** Old value of btr_cur_n_sea. Copied by
|
/** Old value of btr_cur_n_sea. Copied by
|
||||||
srv_refresh_innodb_monitor_stats(). Referenced by
|
srv_refresh_innodb_monitor_stats(). Referenced by
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
|
|
||||||
Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
|
Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
|
||||||
Copyright (c) 2017, 2022, MariaDB Corporation.
|
Copyright (c) 2017, 2023, MariaDB Corporation.
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify it under
|
This program is free software; you can redistribute it and/or modify it under
|
||||||
the terms of the GNU General Public License as published by the Free Software
|
the terms of the GNU General Public License as published by the Free Software
|
||||||
@@ -70,24 +70,6 @@ btr_pcur_init(
|
|||||||
/*==========*/
|
/*==========*/
|
||||||
btr_pcur_t* pcur); /*!< in: persistent cursor */
|
btr_pcur_t* pcur); /*!< in: persistent cursor */
|
||||||
|
|
||||||
/**************************************************************//**
|
|
||||||
Initializes and opens a persistent cursor to an index tree. */
|
|
||||||
inline
|
|
||||||
dberr_t
|
|
||||||
btr_pcur_open(
|
|
||||||
const dtuple_t* tuple, /*!< in: tuple on which search done */
|
|
||||||
page_cur_mode_t mode, /*!< in: PAGE_CUR_L, ...;
|
|
||||||
NOTE that if the search is made using a unique
|
|
||||||
prefix of a record, mode should be
|
|
||||||
PAGE_CUR_LE, not PAGE_CUR_GE, as the latter
|
|
||||||
may end up on the previous page from the
|
|
||||||
record! */
|
|
||||||
btr_latch_mode latch_mode,/*!< in: BTR_SEARCH_LEAF, ... */
|
|
||||||
btr_pcur_t* cursor, /*!< in: memory buffer for persistent cursor */
|
|
||||||
ib_uint64_t autoinc,/*!< in: PAGE_ROOT_AUTO_INC to be written
|
|
||||||
(0 if none) */
|
|
||||||
mtr_t* mtr) /*!< in: mtr */
|
|
||||||
MY_ATTRIBUTE((nonnull, warn_unused_result));
|
|
||||||
/** Opens an persistent cursor to an index tree without initializing the
|
/** Opens an persistent cursor to an index tree without initializing the
|
||||||
cursor.
|
cursor.
|
||||||
@param tuple tuple on which search done
|
@param tuple tuple on which search done
|
||||||
@@ -100,8 +82,7 @@ cursor.
|
|||||||
@param mtr mini-transaction
|
@param mtr mini-transaction
|
||||||
@return DB_SUCCESS on success or error code otherwise. */
|
@return DB_SUCCESS on success or error code otherwise. */
|
||||||
inline
|
inline
|
||||||
dberr_t btr_pcur_open_with_no_init(const dtuple_t *tuple,
|
dberr_t btr_pcur_open_with_no_init(const dtuple_t *tuple, page_cur_mode_t mode,
|
||||||
page_cur_mode_t mode,
|
|
||||||
btr_latch_mode latch_mode,
|
btr_latch_mode latch_mode,
|
||||||
btr_pcur_t *cursor, mtr_t *mtr);
|
btr_pcur_t *cursor, mtr_t *mtr);
|
||||||
|
|
||||||
@@ -356,7 +337,7 @@ struct btr_pcur_t
|
|||||||
/** the modify clock value of the buffer block when the cursor position
|
/** the modify clock value of the buffer block when the cursor position
|
||||||
was stored */
|
was stored */
|
||||||
ib_uint64_t modify_clock= 0;
|
ib_uint64_t modify_clock= 0;
|
||||||
/** btr_pcur_store_position() and btr_pcur_restore_position() state. */
|
/** btr_pcur_store_position() and restore_position() state. */
|
||||||
enum pcur_pos_t pos_state= BTR_PCUR_NOT_POSITIONED;
|
enum pcur_pos_t pos_state= BTR_PCUR_NOT_POSITIONED;
|
||||||
page_cur_mode_t search_mode= PAGE_CUR_UNSUPP;
|
page_cur_mode_t search_mode= PAGE_CUR_UNSUPP;
|
||||||
/** the transaction, if we know it; otherwise this field is not defined;
|
/** the transaction, if we know it; otherwise this field is not defined;
|
||||||
@@ -383,8 +364,8 @@ struct btr_pcur_t
|
|||||||
supremum.
|
supremum.
|
||||||
(4) cursor was positioned before the first or after the last in an
|
(4) cursor was positioned before the first or after the last in an
|
||||||
empty tree: restores to before first or after the last in the tree.
|
empty tree: restores to before first or after the last in the tree.
|
||||||
@param restore_latch_mode BTR_SEARCH_LEAF, ...
|
@param latch_mode BTR_SEARCH_LEAF, ...
|
||||||
@param mtr mtr
|
@param mtr mini-transaction
|
||||||
@retval SAME_ALL cursor position on user rec and points on
|
@retval SAME_ALL cursor position on user rec and points on
|
||||||
the record with the same field values as in the stored record,
|
the record with the same field values as in the stored record,
|
||||||
@retval SAME_UNIQ cursor position is on user rec and points on the
|
@retval SAME_UNIQ cursor position is on user rec and points on the
|
||||||
@@ -409,8 +390,7 @@ struct btr_pcur_t
|
|||||||
pos_state= BTR_PCUR_IS_POSITIONED;
|
pos_state= BTR_PCUR_IS_POSITIONED;
|
||||||
old_rec= nullptr;
|
old_rec= nullptr;
|
||||||
|
|
||||||
return btr_cur.open_leaf(first, index,
|
return btr_cur.open_leaf(first, index, this->latch_mode, mtr);
|
||||||
BTR_LATCH_MODE_WITHOUT_FLAGS(latch_mode), mtr);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -433,6 +413,24 @@ inline rec_t *btr_pcur_get_rec(const btr_pcur_t *cursor)
|
|||||||
return cursor->btr_cur.page_cur.rec;
|
return cursor->btr_cur.page_cur.rec;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**************************************************************//**
|
||||||
|
Initializes and opens a persistent cursor to an index tree. */
|
||||||
|
inline
|
||||||
|
dberr_t
|
||||||
|
btr_pcur_open(
|
||||||
|
const dtuple_t* tuple, /*!< in: tuple on which search done */
|
||||||
|
page_cur_mode_t mode, /*!< in: PAGE_CUR_LE, ... */
|
||||||
|
btr_latch_mode latch_mode,/*!< in: BTR_SEARCH_LEAF, ... */
|
||||||
|
btr_pcur_t* cursor, /*!< in: memory buffer for persistent cursor */
|
||||||
|
mtr_t* mtr) /*!< in: mtr */
|
||||||
|
{
|
||||||
|
cursor->latch_mode= BTR_LATCH_MODE_WITHOUT_FLAGS(latch_mode);
|
||||||
|
cursor->search_mode= mode;
|
||||||
|
cursor->pos_state= BTR_PCUR_IS_POSITIONED;
|
||||||
|
cursor->trx_if_known= nullptr;
|
||||||
|
return cursor->btr_cur.search_leaf(tuple, mode, latch_mode, mtr);
|
||||||
|
}
|
||||||
|
|
||||||
/** Open a cursor on the first user record satisfying the search condition;
|
/** Open a cursor on the first user record satisfying the search condition;
|
||||||
in case of no match, after the last index record. */
|
in case of no match, after the last index record. */
|
||||||
MY_ATTRIBUTE((nonnull, warn_unused_result))
|
MY_ATTRIBUTE((nonnull, warn_unused_result))
|
||||||
@@ -440,16 +438,15 @@ inline
|
|||||||
dberr_t
|
dberr_t
|
||||||
btr_pcur_open_on_user_rec(
|
btr_pcur_open_on_user_rec(
|
||||||
const dtuple_t* tuple, /*!< in: tuple on which search done */
|
const dtuple_t* tuple, /*!< in: tuple on which search done */
|
||||||
page_cur_mode_t mode, /*!< in: PAGE_CUR_L, ... */
|
|
||||||
btr_latch_mode latch_mode, /*!< in: BTR_SEARCH_LEAF or
|
btr_latch_mode latch_mode, /*!< in: BTR_SEARCH_LEAF or
|
||||||
BTR_MODIFY_LEAF */
|
BTR_MODIFY_LEAF */
|
||||||
btr_pcur_t* cursor, /*!< in: memory buffer for persistent
|
btr_pcur_t* cursor, /*!< in: memory buffer for persistent
|
||||||
cursor */
|
cursor */
|
||||||
mtr_t* mtr) /*!< in: mtr */
|
mtr_t* mtr) /*!< in: mtr */
|
||||||
{
|
{
|
||||||
ut_ad(mode == PAGE_CUR_GE || mode == PAGE_CUR_G);
|
|
||||||
ut_ad(latch_mode == BTR_SEARCH_LEAF || latch_mode == BTR_MODIFY_LEAF);
|
ut_ad(latch_mode == BTR_SEARCH_LEAF || latch_mode == BTR_MODIFY_LEAF);
|
||||||
if (dberr_t err= btr_pcur_open(tuple, mode, latch_mode, cursor, 0, mtr))
|
if (dberr_t err=
|
||||||
|
btr_pcur_open(tuple, PAGE_CUR_GE, latch_mode, cursor, mtr))
|
||||||
return err;
|
return err;
|
||||||
if (!btr_pcur_is_after_last_on_page(cursor) ||
|
if (!btr_pcur_is_after_last_on_page(cursor) ||
|
||||||
btr_pcur_is_after_last_in_tree(cursor))
|
btr_pcur_is_after_last_in_tree(cursor))
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
|
|
||||||
Copyright (c) 1996, 2015, Oracle and/or its affiliates. All Rights Reserved.
|
Copyright (c) 1996, 2015, Oracle and/or its affiliates. All Rights Reserved.
|
||||||
Copyright (c) 2015, 2022, MariaDB Corporation.
|
Copyright (c) 2015, 2023, MariaDB Corporation.
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify it under
|
This program is free software; you can redistribute it and/or modify it under
|
||||||
the terms of the GNU General Public License as published by the Free Software
|
the terms of the GNU General Public License as published by the Free Software
|
||||||
@@ -299,38 +299,10 @@ btr_pcur_init(
|
|||||||
pcur->btr_cur.rtr_info = NULL;
|
pcur->btr_cur.rtr_info = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**************************************************************//**
|
|
||||||
Initializes and opens a persistent cursor to an index tree. */
|
|
||||||
inline
|
|
||||||
dberr_t
|
|
||||||
btr_pcur_open(
|
|
||||||
const dtuple_t* tuple, /*!< in: tuple on which search done */
|
|
||||||
page_cur_mode_t mode, /*!< in: PAGE_CUR_L, ...;
|
|
||||||
NOTE that if the search is made using a unique
|
|
||||||
prefix of a record, mode should be
|
|
||||||
PAGE_CUR_LE, not PAGE_CUR_GE, as the latter
|
|
||||||
may end up on the previous page from the
|
|
||||||
record! */
|
|
||||||
btr_latch_mode latch_mode,/*!< in: BTR_SEARCH_LEAF, ... */
|
|
||||||
btr_pcur_t* cursor, /*!< in: memory buffer for persistent cursor */
|
|
||||||
ib_uint64_t autoinc,/*!< in: PAGE_ROOT_AUTO_INC to be written
|
|
||||||
(0 if none) */
|
|
||||||
mtr_t* mtr) /*!< in: mtr */
|
|
||||||
{
|
|
||||||
ut_ad(!cursor->index()->is_spatial());
|
|
||||||
cursor->latch_mode= BTR_LATCH_MODE_WITHOUT_FLAGS(latch_mode);
|
|
||||||
cursor->search_mode= mode;
|
|
||||||
cursor->pos_state= BTR_PCUR_IS_POSITIONED;
|
|
||||||
cursor->trx_if_known= nullptr;
|
|
||||||
return btr_cur_search_to_nth_level(0, tuple, mode, latch_mode,
|
|
||||||
btr_pcur_get_btr_cur(cursor),
|
|
||||||
mtr, autoinc);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Opens an persistent cursor to an index tree without initializing the
|
/** Opens an persistent cursor to an index tree without initializing the
|
||||||
cursor.
|
cursor.
|
||||||
@param tuple tuple on which search done
|
@param tuple tuple on which search done
|
||||||
@param mode PAGE_CUR_L, ...; NOTE that if the search is made using a
|
@param mode search mode; NOTE that if the search is made using a
|
||||||
unique prefix of a record, mode should be PAGE_CUR_LE, not
|
unique prefix of a record, mode should be PAGE_CUR_LE, not
|
||||||
PAGE_CUR_GE, as the latter may end up on the previous page of
|
PAGE_CUR_GE, as the latter may end up on the previous page of
|
||||||
the record!
|
the record!
|
||||||
@@ -339,8 +311,7 @@ cursor.
|
|||||||
@param mtr mini-transaction
|
@param mtr mini-transaction
|
||||||
@return DB_SUCCESS on success or error code otherwise. */
|
@return DB_SUCCESS on success or error code otherwise. */
|
||||||
inline
|
inline
|
||||||
dberr_t btr_pcur_open_with_no_init(const dtuple_t *tuple,
|
dberr_t btr_pcur_open_with_no_init(const dtuple_t *tuple, page_cur_mode_t mode,
|
||||||
page_cur_mode_t mode,
|
|
||||||
btr_latch_mode latch_mode,
|
btr_latch_mode latch_mode,
|
||||||
btr_pcur_t *cursor, mtr_t *mtr)
|
btr_pcur_t *cursor, mtr_t *mtr)
|
||||||
{
|
{
|
||||||
@@ -348,10 +319,7 @@ dberr_t btr_pcur_open_with_no_init(const dtuple_t *tuple,
|
|||||||
cursor->search_mode= mode;
|
cursor->search_mode= mode;
|
||||||
cursor->pos_state= BTR_PCUR_IS_POSITIONED;
|
cursor->pos_state= BTR_PCUR_IS_POSITIONED;
|
||||||
cursor->trx_if_known= nullptr;
|
cursor->trx_if_known= nullptr;
|
||||||
|
return cursor->btr_cur.search_leaf(tuple, mode, latch_mode, mtr);
|
||||||
/* Search with the tree cursor */
|
|
||||||
return btr_cur_search_to_nth_level(0, tuple, mode, latch_mode,
|
|
||||||
btr_pcur_get_btr_cur(cursor), mtr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**************************************************************//**
|
/**************************************************************//**
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
|
|
||||||
Copyright (c) 1996, 2015, Oracle and/or its affiliates. All Rights Reserved.
|
Copyright (c) 1996, 2015, Oracle and/or its affiliates. All Rights Reserved.
|
||||||
Copyright (c) 2018, 2022, MariaDB Corporation.
|
Copyright (c) 2018, 2023, MariaDB Corporation.
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify it under
|
This program is free software; you can redistribute it and/or modify it under
|
||||||
the terms of the GNU General Public License as published by the Free Software
|
the terms of the GNU General Public License as published by the Free Software
|
||||||
@@ -55,25 +55,26 @@ in the index record. */
|
|||||||
#define BTR_EXTERN_LOCAL_STORED_MAX_SIZE \
|
#define BTR_EXTERN_LOCAL_STORED_MAX_SIZE \
|
||||||
(BTR_EXTERN_FIELD_REF_SIZE * 2)
|
(BTR_EXTERN_FIELD_REF_SIZE * 2)
|
||||||
|
|
||||||
/** Latching modes for btr_cur_search_to_nth_level(). */
|
/** Latching modes for btr_cur_t::search_leaf(). */
|
||||||
enum btr_latch_mode {
|
enum btr_latch_mode {
|
||||||
/** Search a record on a leaf page and S-latch it. */
|
/** Search a record on a leaf page and S-latch it. */
|
||||||
BTR_SEARCH_LEAF = RW_S_LATCH,
|
BTR_SEARCH_LEAF = RW_S_LATCH,
|
||||||
/** (Prepare to) modify a record on a leaf page and X-latch it. */
|
/** (Prepare to) modify a record on a leaf page and X-latch it. */
|
||||||
BTR_MODIFY_LEAF = RW_X_LATCH,
|
BTR_MODIFY_LEAF = RW_X_LATCH,
|
||||||
|
/** U-latch root and X-latch a leaf page */
|
||||||
|
BTR_MODIFY_ROOT_AND_LEAF = RW_SX_LATCH,
|
||||||
/** Obtain no latches. */
|
/** Obtain no latches. */
|
||||||
BTR_NO_LATCHES = RW_NO_LATCH,
|
BTR_NO_LATCHES = RW_NO_LATCH,
|
||||||
/** Search the previous record. */
|
/** Search the previous record.
|
||||||
|
Used in btr_pcur_move_backward_from_page(). */
|
||||||
BTR_SEARCH_PREV = 4 | BTR_SEARCH_LEAF,
|
BTR_SEARCH_PREV = 4 | BTR_SEARCH_LEAF,
|
||||||
/** Modify the previous record. */
|
/** Modify the previous record.
|
||||||
|
Used in btr_pcur_move_backward_from_page() and ibuf_insert(). */
|
||||||
BTR_MODIFY_PREV = 4 | BTR_MODIFY_LEAF,
|
BTR_MODIFY_PREV = 4 | BTR_MODIFY_LEAF,
|
||||||
/** Start searching the entire B-tree. */
|
/** Start modifying the entire B-tree. */
|
||||||
BTR_SEARCH_TREE = 8 | BTR_SEARCH_LEAF,
|
|
||||||
/** Start modifying1 the entire B-tree. */
|
|
||||||
BTR_MODIFY_TREE = 8 | BTR_MODIFY_LEAF,
|
BTR_MODIFY_TREE = 8 | BTR_MODIFY_LEAF,
|
||||||
/** Continue searching the entire B-tree. */
|
/** Continue modifying the entire R-tree.
|
||||||
BTR_CONT_SEARCH_TREE = 4 | BTR_SEARCH_TREE,
|
Only used by rtr_search_to_nth_level(). */
|
||||||
/** Continue modifying the entire B-tree. */
|
|
||||||
BTR_CONT_MODIFY_TREE = 4 | BTR_MODIFY_TREE,
|
BTR_CONT_MODIFY_TREE = 4 | BTR_MODIFY_TREE,
|
||||||
|
|
||||||
/* BTR_INSERT, BTR_DELETE and BTR_DELETE_MARK are mutually
|
/* BTR_INSERT, BTR_DELETE and BTR_DELETE_MARK are mutually
|
||||||
@@ -98,14 +99,14 @@ enum btr_latch_mode {
|
|||||||
dict_index_t::lock S-latch is being held. */
|
dict_index_t::lock S-latch is being held. */
|
||||||
BTR_SEARCH_LEAF_ALREADY_S_LATCHED = BTR_SEARCH_LEAF
|
BTR_SEARCH_LEAF_ALREADY_S_LATCHED = BTR_SEARCH_LEAF
|
||||||
| BTR_ALREADY_S_LATCHED,
|
| BTR_ALREADY_S_LATCHED,
|
||||||
/** Search the entire index tree, assuming that the
|
|
||||||
dict_index_t::lock S-latch is being held. */
|
|
||||||
BTR_SEARCH_TREE_ALREADY_S_LATCHED = BTR_SEARCH_TREE
|
|
||||||
| BTR_ALREADY_S_LATCHED,
|
|
||||||
/** Search and X-latch a leaf page, assuming that the
|
/** Search and X-latch a leaf page, assuming that the
|
||||||
dict_index_t::lock is being held in non-exclusive mode. */
|
dict_index_t::lock is being held in non-exclusive mode. */
|
||||||
BTR_MODIFY_LEAF_ALREADY_LATCHED = BTR_MODIFY_LEAF
|
BTR_MODIFY_LEAF_ALREADY_LATCHED = BTR_MODIFY_LEAF
|
||||||
| BTR_ALREADY_S_LATCHED,
|
| BTR_ALREADY_S_LATCHED,
|
||||||
|
/** U-latch root and X-latch a leaf page, assuming that
|
||||||
|
dict_index_t::lock is being held in U mode. */
|
||||||
|
BTR_MODIFY_ROOT_AND_LEAF_ALREADY_LATCHED = BTR_MODIFY_ROOT_AND_LEAF
|
||||||
|
| BTR_ALREADY_S_LATCHED,
|
||||||
|
|
||||||
/** Attempt to delete-mark a secondary index record. */
|
/** Attempt to delete-mark a secondary index record. */
|
||||||
BTR_DELETE_MARK_LEAF = BTR_MODIFY_LEAF | BTR_DELETE_MARK,
|
BTR_DELETE_MARK_LEAF = BTR_MODIFY_LEAF | BTR_DELETE_MARK,
|
||||||
@@ -132,6 +133,9 @@ enum btr_latch_mode {
|
|||||||
|
|
||||||
/** Attempt to delete a record in the tree. */
|
/** Attempt to delete a record in the tree. */
|
||||||
BTR_PURGE_TREE = BTR_MODIFY_TREE | BTR_LATCH_FOR_DELETE,
|
BTR_PURGE_TREE = BTR_MODIFY_TREE | BTR_LATCH_FOR_DELETE,
|
||||||
|
/** Attempt to delete a record in an x-latched tree. */
|
||||||
|
BTR_PURGE_TREE_ALREADY_LATCHED = BTR_PURGE_TREE
|
||||||
|
| BTR_ALREADY_S_LATCHED,
|
||||||
|
|
||||||
/** Attempt to insert a record into the tree. */
|
/** Attempt to insert a record into the tree. */
|
||||||
BTR_INSERT_TREE = BTR_MODIFY_TREE | BTR_LATCH_FOR_INSERT,
|
BTR_INSERT_TREE = BTR_MODIFY_TREE | BTR_LATCH_FOR_INSERT,
|
||||||
|
@@ -799,7 +799,7 @@ public:
|
|||||||
{
|
{
|
||||||
ut_ad(fsp_is_system_temporary(id().space()));
|
ut_ad(fsp_is_system_temporary(id().space()));
|
||||||
ut_ad(in_file());
|
ut_ad(in_file());
|
||||||
ut_ad(!oldest_modification() || oldest_modification() == 2);
|
ut_ad((oldest_modification() | 2) == 2);
|
||||||
oldest_modification_= 2;
|
oldest_modification_= 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
|
|
||||||
Copyright (c) 2014, 2016, Oracle and/or its affiliates. All Rights Reserved.
|
Copyright (c) 2014, 2016, Oracle and/or its affiliates. All Rights Reserved.
|
||||||
Copyright (c) 2017, 2022, MariaDB Corporation.
|
Copyright (c) 2017, 2023, MariaDB Corporation.
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify it under
|
This program is free software; you can redistribute it and/or modify it under
|
||||||
the terms of the GNU General Public License as published by the Free Software
|
the terms of the GNU General Public License as published by the Free Software
|
||||||
@@ -59,6 +59,44 @@ Created 2013/03/27 Jimmy Yang and Allen Lai
|
|||||||
|
|
||||||
/* Geometry data header */
|
/* Geometry data header */
|
||||||
#define GEO_DATA_HEADER_SIZE 4
|
#define GEO_DATA_HEADER_SIZE 4
|
||||||
|
|
||||||
|
/** Search for a spatial index leaf page record.
|
||||||
|
@param cur cursor
|
||||||
|
@param tuple search tuple
|
||||||
|
@param latch_mode latching mode
|
||||||
|
@param mtr mini-transaction
|
||||||
|
@param mode search mode */
|
||||||
|
dberr_t rtr_search_leaf(btr_cur_t *cur, const dtuple_t *tuple,
|
||||||
|
btr_latch_mode latch_mode, mtr_t *mtr,
|
||||||
|
page_cur_mode_t mode= PAGE_CUR_RTREE_LOCATE)
|
||||||
|
MY_ATTRIBUTE((nonnull, warn_unused_result));
|
||||||
|
|
||||||
|
/** Search for inserting a spatial index leaf page record.
|
||||||
|
@param cur cursor
|
||||||
|
@param tuple search tuple
|
||||||
|
@param latch_mode latching mode
|
||||||
|
@param mtr mini-transaction */
|
||||||
|
inline dberr_t rtr_insert_leaf(btr_cur_t *cur, const dtuple_t *tuple,
|
||||||
|
btr_latch_mode latch_mode, mtr_t *mtr)
|
||||||
|
{
|
||||||
|
return rtr_search_leaf(cur, tuple, latch_mode, mtr, PAGE_CUR_RTREE_INSERT);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Search for a spatial index leaf page record.
|
||||||
|
@param pcur cursor
|
||||||
|
@param tuple search tuple
|
||||||
|
@param mode search mode
|
||||||
|
@param mtr mini-transaction */
|
||||||
|
dberr_t rtr_search_leaf(btr_pcur_t *pcur, const dtuple_t *tuple,
|
||||||
|
page_cur_mode_t mode, mtr_t *mtr)
|
||||||
|
MY_ATTRIBUTE((nonnull, warn_unused_result));
|
||||||
|
|
||||||
|
dberr_t rtr_search_to_nth_level(ulint level, const dtuple_t *tuple,
|
||||||
|
page_cur_mode_t mode,
|
||||||
|
btr_latch_mode latch_mode,
|
||||||
|
btr_cur_t *cur, mtr_t *mtr)
|
||||||
|
MY_ATTRIBUTE((nonnull, warn_unused_result));
|
||||||
|
|
||||||
/**********************************************************************//**
|
/**********************************************************************//**
|
||||||
Builds a Rtree node pointer out of a physical record and a page number.
|
Builds a Rtree node pointer out of a physical record and a page number.
|
||||||
@return own: node pointer */
|
@return own: node pointer */
|
||||||
@@ -295,11 +333,9 @@ rtr_store_parent_path(
|
|||||||
/**************************************************************//**
|
/**************************************************************//**
|
||||||
Initializes and opens a persistent cursor to an index tree. It should be
|
Initializes and opens a persistent cursor to an index tree. It should be
|
||||||
closed with btr_pcur_close. */
|
closed with btr_pcur_close. */
|
||||||
bool
|
bool rtr_search(
|
||||||
rtr_pcur_open(
|
|
||||||
dict_index_t* index, /*!< in: index */
|
|
||||||
const dtuple_t* tuple, /*!< in: tuple on which search done */
|
const dtuple_t* tuple, /*!< in: tuple on which search done */
|
||||||
btr_latch_mode latch_mode,/*!< in: BTR_SEARCH_LEAF, ... */
|
btr_latch_mode latch_mode,/*!< in: BTR_MODIFY_LEAF, ... */
|
||||||
btr_pcur_t* cursor, /*!< in: memory buffer for persistent cursor */
|
btr_pcur_t* cursor, /*!< in: memory buffer for persistent cursor */
|
||||||
mtr_t* mtr) /*!< in: mtr */
|
mtr_t* mtr) /*!< in: mtr */
|
||||||
MY_ATTRIBUTE((warn_unused_result));
|
MY_ATTRIBUTE((warn_unused_result));
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
|
|
||||||
Copyright (c) 2014, Oracle and/or its affiliates. All Rights Reserved.
|
Copyright (c) 2014, Oracle and/or its affiliates. All Rights Reserved.
|
||||||
Copyright (c) 2018, 2020, MariaDB Corporation.
|
Copyright (c) 2018, 2023, MariaDB Corporation.
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify it under
|
This program is free software; you can redistribute it and/or modify it under
|
||||||
the terms of the GNU General Public License as published by the Free Software
|
the terms of the GNU General Public License as published by the Free Software
|
||||||
@@ -105,12 +105,6 @@ typedef struct rtr_info{
|
|||||||
matched_rec_t* matches;/*!< struct holding matching leaf records */
|
matched_rec_t* matches;/*!< struct holding matching leaf records */
|
||||||
mysql_mutex_t rtr_path_mutex;
|
mysql_mutex_t rtr_path_mutex;
|
||||||
/*!< mutex protect the "path" vector */
|
/*!< mutex protect the "path" vector */
|
||||||
buf_block_t* tree_blocks[RTR_MAX_LEVELS + RTR_LEAF_LATCH_NUM];
|
|
||||||
/*!< tracking pages that would be locked
|
|
||||||
at leaf level, for future free */
|
|
||||||
ulint tree_savepoints[RTR_MAX_LEVELS + RTR_LEAF_LATCH_NUM];
|
|
||||||
/*!< savepoint used to release latches/blocks
|
|
||||||
on each level and leaf level */
|
|
||||||
rtr_mbr_t mbr; /*!< the search MBR */
|
rtr_mbr_t mbr; /*!< the search MBR */
|
||||||
que_thr_t* thr; /*!< the search thread */
|
que_thr_t* thr; /*!< the search thread */
|
||||||
mem_heap_t* heap; /*!< memory heap */
|
mem_heap_t* heap; /*!< memory heap */
|
||||||
|
@@ -100,8 +100,8 @@ ibuf_should_try(
|
|||||||
a secondary index when we
|
a secondary index when we
|
||||||
decide */
|
decide */
|
||||||
{
|
{
|
||||||
if (!innodb_change_buffering || !ibuf.max_size || index->is_clust() ||
|
if (index->type & (DICT_CLUSTERED | DICT_IBUF | DICT_SPATIAL) ||
|
||||||
index->is_spatial())
|
!innodb_change_buffering || !ibuf.max_size)
|
||||||
return false;
|
return false;
|
||||||
if (!ignore_sec_unique && index->is_unique())
|
if (!ignore_sec_unique && index->is_unique())
|
||||||
return false;
|
return false;
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
|
|
||||||
Copyright (c) 2019, 2022, MariaDB Corporation.
|
Copyright (c) 2019, 2023, MariaDB Corporation.
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify it under
|
This program is free software; you can redistribute it and/or modify it under
|
||||||
the terms of the GNU General Public License as published by the Free Software
|
the terms of the GNU General Public License as published by the Free Software
|
||||||
@@ -402,7 +402,8 @@ inline byte *mtr_t::log_write(const page_id_t id, const buf_page_t *bpage,
|
|||||||
ut_ad(have_offset || offset == 0);
|
ut_ad(have_offset || offset == 0);
|
||||||
ut_ad(offset + len <= srv_page_size);
|
ut_ad(offset + len <= srv_page_size);
|
||||||
static_assert(MIN_4BYTE >= UNIV_PAGE_SIZE_MAX, "consistency");
|
static_assert(MIN_4BYTE >= UNIV_PAGE_SIZE_MAX, "consistency");
|
||||||
|
ut_ad(type == FREE_PAGE || type == OPTION || (type == EXTENDED && !bpage) ||
|
||||||
|
memo_contains_flagged(bpage, MTR_MEMO_MODIFY));
|
||||||
size_t max_len;
|
size_t max_len;
|
||||||
if (!have_len)
|
if (!have_len)
|
||||||
max_len= 1 + 5 + 5;
|
max_len= 1 + 5 + 5;
|
||||||
@@ -512,33 +513,6 @@ inline void mtr_t::memcpy(const buf_block_t &b, void *dest, const void *str,
|
|||||||
memcpy(b, ut_align_offset(d, srv_page_size), len);
|
memcpy(b, ut_align_offset(d, srv_page_size), len);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Initialize an entire page.
|
|
||||||
@param[in,out] b buffer page */
|
|
||||||
inline void mtr_t::init(buf_block_t *b)
|
|
||||||
{
|
|
||||||
const page_id_t id{b->page.id()};
|
|
||||||
ut_ad(is_named_space(id.space()));
|
|
||||||
ut_ad(!m_freed_pages == !m_freed_space);
|
|
||||||
|
|
||||||
if (UNIV_LIKELY_NULL(m_freed_space) &&
|
|
||||||
m_freed_space->id == id.space() &&
|
|
||||||
m_freed_pages->remove_if_exists(b->page.id().page_no()) &&
|
|
||||||
m_freed_pages->empty())
|
|
||||||
{
|
|
||||||
delete m_freed_pages;
|
|
||||||
m_freed_pages= nullptr;
|
|
||||||
m_freed_space= nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
b->page.set_reinit(b->page.state() & buf_page_t::LRU_MASK);
|
|
||||||
|
|
||||||
if (!is_logged())
|
|
||||||
return;
|
|
||||||
|
|
||||||
m_log.close(log_write<INIT_PAGE>(b->page.id(), &b->page));
|
|
||||||
m_last_offset= FIL_PAGE_TYPE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Write an EXTENDED log record.
|
/** Write an EXTENDED log record.
|
||||||
@param block buffer pool page
|
@param block buffer pool page
|
||||||
@param type extended record subtype; @see mrec_ext_t */
|
@param type extended record subtype; @see mrec_ext_t */
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
|
|
||||||
Copyright (c) 1995, 2017, Oracle and/or its affiliates. All Rights Reserved.
|
Copyright (c) 1995, 2017, Oracle and/or its affiliates. All Rights Reserved.
|
||||||
Copyright (c) 2013, 2022, MariaDB Corporation.
|
Copyright (c) 2013, 2023, MariaDB Corporation.
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify it under
|
This program is free software; you can redistribute it and/or modify it under
|
||||||
the terms of the GNU General Public License as published by the Free Software
|
the terms of the GNU General Public License as published by the Free Software
|
||||||
@@ -29,7 +29,7 @@ Created 11/26/1995 Heikki Tuuri
|
|||||||
#include "fil0fil.h"
|
#include "fil0fil.h"
|
||||||
#include "dyn0buf.h"
|
#include "dyn0buf.h"
|
||||||
#include "buf0buf.h"
|
#include "buf0buf.h"
|
||||||
#include <vector>
|
#include "small_vector.h"
|
||||||
|
|
||||||
/** Start a mini-transaction. */
|
/** Start a mini-transaction. */
|
||||||
#define mtr_start(m) (m)->start()
|
#define mtr_start(m) (m)->start()
|
||||||
@@ -37,15 +37,6 @@ Created 11/26/1995 Heikki Tuuri
|
|||||||
/** Commit a mini-transaction. */
|
/** Commit a mini-transaction. */
|
||||||
#define mtr_commit(m) (m)->commit()
|
#define mtr_commit(m) (m)->commit()
|
||||||
|
|
||||||
/** Set and return a savepoint in mtr.
|
|
||||||
@return savepoint */
|
|
||||||
#define mtr_set_savepoint(m) (m)->get_savepoint()
|
|
||||||
|
|
||||||
/** Release the (index tree) s-latch stored in an mtr memo after a
|
|
||||||
savepoint. */
|
|
||||||
#define mtr_release_s_latch_at_savepoint(m, s, l) \
|
|
||||||
(m)->release_s_latch_at_savepoint((s), (l))
|
|
||||||
|
|
||||||
/** Change the logging mode of a mini-transaction.
|
/** Change the logging mode of a mini-transaction.
|
||||||
@return old mode */
|
@return old mode */
|
||||||
#define mtr_set_log_mode(m, d) (m)->set_log_mode((d))
|
#define mtr_set_log_mode(m, d) (m)->set_log_mode((d))
|
||||||
@@ -60,13 +51,10 @@ savepoint. */
|
|||||||
# define mtr_sx_lock_index(i,m) (m)->u_lock(&(i)->lock)
|
# define mtr_sx_lock_index(i,m) (m)->u_lock(&(i)->lock)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define mtr_release_block_at_savepoint(m, s, b) \
|
|
||||||
(m)->release_block_at_savepoint((s), (b))
|
|
||||||
|
|
||||||
/** Mini-transaction memo stack slot. */
|
/** Mini-transaction memo stack slot. */
|
||||||
struct mtr_memo_slot_t
|
struct mtr_memo_slot_t
|
||||||
{
|
{
|
||||||
/** pointer to the object, or nullptr if released */
|
/** pointer to the object */
|
||||||
void *object;
|
void *object;
|
||||||
/** type of the stored object */
|
/** type of the stored object */
|
||||||
mtr_memo_type_t type;
|
mtr_memo_type_t type;
|
||||||
@@ -77,6 +65,9 @@ struct mtr_memo_slot_t
|
|||||||
|
|
||||||
/** Mini-transaction handle and buffer */
|
/** Mini-transaction handle and buffer */
|
||||||
struct mtr_t {
|
struct mtr_t {
|
||||||
|
mtr_t();
|
||||||
|
~mtr_t();
|
||||||
|
|
||||||
/** Start a mini-transaction. */
|
/** Start a mini-transaction. */
|
||||||
void start();
|
void start();
|
||||||
|
|
||||||
@@ -91,11 +82,11 @@ struct mtr_t {
|
|||||||
/** Release latches of unmodified buffer pages.
|
/** Release latches of unmodified buffer pages.
|
||||||
@param begin first slot to release */
|
@param begin first slot to release */
|
||||||
void rollback_to_savepoint(ulint begin)
|
void rollback_to_savepoint(ulint begin)
|
||||||
{ rollback_to_savepoint(begin, m_memo->size()); }
|
{ rollback_to_savepoint(begin, m_memo.size()); }
|
||||||
|
|
||||||
/** Release the last acquired buffer page latch. */
|
/** Release the last acquired buffer page latch. */
|
||||||
void release_last_page()
|
void release_last_page()
|
||||||
{ auto s= m_memo->size(); rollback_to_savepoint(s - 1, s); }
|
{ auto s= m_memo.size(); rollback_to_savepoint(s - 1, s); }
|
||||||
|
|
||||||
/** Commit a mini-transaction that is shrinking a tablespace.
|
/** Commit a mini-transaction that is shrinking a tablespace.
|
||||||
@param space tablespace that is being shrunk */
|
@param space tablespace that is being shrunk */
|
||||||
@@ -120,86 +111,39 @@ struct mtr_t {
|
|||||||
ulint get_savepoint() const
|
ulint get_savepoint() const
|
||||||
{
|
{
|
||||||
ut_ad(is_active());
|
ut_ad(is_active());
|
||||||
return m_memo ? m_memo->size() : 0;
|
return m_memo.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Release the (index tree) s-latch stored in an mtr memo after a savepoint.
|
/** Get the block at a savepoint */
|
||||||
@param savepoint value returned by get_savepoint()
|
buf_block_t *at_savepoint(ulint savepoint) const
|
||||||
@param lock index latch to release */
|
|
||||||
void release_s_latch_at_savepoint(ulint savepoint, index_lock *lock)
|
|
||||||
{
|
{
|
||||||
ut_ad(is_active());
|
ut_ad(is_active());
|
||||||
mtr_memo_slot_t &slot= m_memo->at(savepoint);
|
const mtr_memo_slot_t &slot= m_memo[savepoint];
|
||||||
ut_ad(slot.object == lock);
|
ut_ad(slot.type < MTR_MEMO_S_LOCK);
|
||||||
ut_ad(slot.type == MTR_MEMO_S_LOCK);
|
ut_ad(slot.object);
|
||||||
slot.object= nullptr;
|
return static_cast<buf_block_t*>(slot.object);
|
||||||
lock->s_unlock();
|
|
||||||
}
|
}
|
||||||
/** Release the block in an mtr memo after a savepoint. */
|
|
||||||
void release_block_at_savepoint(ulint savepoint, buf_block_t *block)
|
/** Try to get a block at a savepoint.
|
||||||
|
@param savepoint the savepoint right before the block was acquired
|
||||||
|
@return the block at the savepoint
|
||||||
|
@retval nullptr if no buffer block was registered at that savepoint */
|
||||||
|
buf_block_t *block_at_savepoint(ulint savepoint) const
|
||||||
{
|
{
|
||||||
ut_ad(is_active());
|
ut_ad(is_active());
|
||||||
mtr_memo_slot_t &slot= m_memo->at(savepoint);
|
const mtr_memo_slot_t &slot= m_memo[savepoint];
|
||||||
ut_ad(slot.object == block);
|
return slot.type < MTR_MEMO_S_LOCK
|
||||||
ut_ad(!(slot.type & MTR_MEMO_MODIFY));
|
? static_cast<buf_block_t*>(slot.object)
|
||||||
slot.object= nullptr;
|
: nullptr;
|
||||||
block->page.unfix();
|
|
||||||
|
|
||||||
switch (slot.type) {
|
|
||||||
case MTR_MEMO_PAGE_S_FIX:
|
|
||||||
block->page.lock.s_unlock();
|
|
||||||
break;
|
|
||||||
case MTR_MEMO_PAGE_SX_FIX:
|
|
||||||
case MTR_MEMO_PAGE_X_FIX:
|
|
||||||
block->page.lock.u_or_x_unlock(slot.type == MTR_MEMO_PAGE_SX_FIX);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return if we are about to make a clean buffer block dirty */
|
/** Retrieve a page that has already been latched.
|
||||||
static bool is_block_dirtied(const buf_page_t &b)
|
@param id page identifier
|
||||||
{
|
@param type page latch type
|
||||||
ut_ad(b.in_file());
|
@return block
|
||||||
ut_ad(b.frame);
|
@retval nullptr if the block had not been latched yet */
|
||||||
ut_ad(b.buf_fix_count());
|
buf_block_t *get_already_latched(const page_id_t id, mtr_memo_type_t type)
|
||||||
return b.oldest_modification() <= 1 && b.id().space() < SRV_TMP_SPACE_ID;
|
const;
|
||||||
}
|
|
||||||
|
|
||||||
/** X-latch a not yet latched block after a savepoint. */
|
|
||||||
void x_latch_at_savepoint(ulint savepoint, buf_block_t *block)
|
|
||||||
{
|
|
||||||
ut_ad(is_active());
|
|
||||||
ut_ad(!memo_contains_flagged(block, MTR_MEMO_PAGE_S_FIX |
|
|
||||||
MTR_MEMO_PAGE_X_FIX | MTR_MEMO_PAGE_SX_FIX));
|
|
||||||
mtr_memo_slot_t &slot= m_memo->at(savepoint);
|
|
||||||
ut_ad(slot.object == block);
|
|
||||||
ut_ad(slot.type == MTR_MEMO_BUF_FIX);
|
|
||||||
slot.type= MTR_MEMO_PAGE_X_FIX;
|
|
||||||
block->page.lock.x_lock();
|
|
||||||
ut_ad(!block->page.is_io_fixed());
|
|
||||||
|
|
||||||
if (!m_made_dirty)
|
|
||||||
m_made_dirty= is_block_dirtied(block->page);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** U-latch a not yet latched block after a savepoint. */
|
|
||||||
void sx_latch_at_savepoint(ulint savepoint, buf_block_t *block)
|
|
||||||
{
|
|
||||||
ut_ad(is_active());
|
|
||||||
ut_ad(!memo_contains_flagged(block, MTR_MEMO_PAGE_S_FIX |
|
|
||||||
MTR_MEMO_PAGE_X_FIX | MTR_MEMO_PAGE_SX_FIX));
|
|
||||||
mtr_memo_slot_t &slot= m_memo->at(savepoint);
|
|
||||||
ut_ad(slot.object == block);
|
|
||||||
ut_ad(slot.type == MTR_MEMO_BUF_FIX);
|
|
||||||
slot.type= MTR_MEMO_PAGE_SX_FIX;
|
|
||||||
block->page.lock.u_lock();
|
|
||||||
ut_ad(!block->page.is_io_fixed());
|
|
||||||
|
|
||||||
if (!m_made_dirty)
|
|
||||||
m_made_dirty= is_block_dirtied(block->page);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @return the logging mode */
|
/** @return the logging mode */
|
||||||
mtr_log_t get_log_mode() const
|
mtr_log_t get_log_mode() const
|
||||||
@@ -358,23 +302,17 @@ struct mtr_t {
|
|||||||
void release(const index_lock &lock) { release(&lock); }
|
void release(const index_lock &lock) { release(&lock); }
|
||||||
/** Release a latch to an unmodified page. */
|
/** Release a latch to an unmodified page. */
|
||||||
void release(const buf_block_t &block) { release(&block); }
|
void release(const buf_block_t &block) { release(&block); }
|
||||||
|
|
||||||
/** Note that the mini-transaction will modify data. */
|
|
||||||
void flag_modified() { m_modifications = true; }
|
|
||||||
private:
|
private:
|
||||||
/** Release an unmodified object. */
|
/** Release an unmodified object. */
|
||||||
void release(const void *object);
|
void release(const void *object);
|
||||||
|
public:
|
||||||
/** Mark the given latched page as modified.
|
/** Mark the given latched page as modified.
|
||||||
@param block page that will be modified */
|
@param block page that will be modified */
|
||||||
void modify(const buf_block_t& block);
|
void set_modified(const buf_block_t &block);
|
||||||
public:
|
|
||||||
/** Note that the mini-transaction will modify a block. */
|
|
||||||
void set_modified(const buf_block_t &block)
|
|
||||||
{ flag_modified(); if (m_log_mode != MTR_LOG_NONE) modify(block); }
|
|
||||||
|
|
||||||
/** Set the state to not-modified. This will not log the changes.
|
/** Set the state to not-modified. This will not log the changes.
|
||||||
This is only used during redo log apply, to avoid logging the changes. */
|
This is only used during redo log apply, to avoid logging the changes. */
|
||||||
void discard_modifications() { m_modifications = false; }
|
void discard_modifications() { m_modifications= false; }
|
||||||
|
|
||||||
/** Get the LSN of commit().
|
/** Get the LSN of commit().
|
||||||
@return the commit LSN
|
@return the commit LSN
|
||||||
@@ -403,28 +341,17 @@ public:
|
|||||||
@param rw_latch latch to acquire */
|
@param rw_latch latch to acquire */
|
||||||
void upgrade_buffer_fix(ulint savepoint, rw_lock_type_t rw_latch);
|
void upgrade_buffer_fix(ulint savepoint, rw_lock_type_t rw_latch);
|
||||||
|
|
||||||
/** Register a page latch on a buffer-fixed block was buffer-fixed.
|
/** Register a change to the page latch state. */
|
||||||
@param latch latch type */
|
void lock_register(ulint savepoint, mtr_memo_type_t type)
|
||||||
void u_lock_register(ulint savepoint)
|
|
||||||
{
|
{
|
||||||
mtr_memo_slot_t &slot= m_memo->at(savepoint);
|
mtr_memo_slot_t &slot= m_memo[savepoint];
|
||||||
ut_ad(slot.type == MTR_MEMO_BUF_FIX);
|
ut_ad(slot.type <= MTR_MEMO_BUF_FIX);
|
||||||
slot.type= MTR_MEMO_PAGE_SX_FIX;
|
ut_ad(type <= MTR_MEMO_BUF_FIX);
|
||||||
}
|
slot.type= type;
|
||||||
|
|
||||||
/** Register a page latch on a buffer-fixed block was buffer-fixed.
|
|
||||||
@param latch latch type */
|
|
||||||
void s_lock_register(ulint savepoint)
|
|
||||||
{
|
|
||||||
mtr_memo_slot_t &slot= m_memo->at(savepoint);
|
|
||||||
ut_ad(slot.type == MTR_MEMO_BUF_FIX);
|
|
||||||
slot.type= MTR_MEMO_PAGE_S_FIX;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Upgrade U locks on a block to X */
|
/** Upgrade U locks on a block to X */
|
||||||
void page_lock_upgrade(const buf_block_t &block);
|
void page_lock_upgrade(const buf_block_t &block);
|
||||||
/** Upgrade U lock to X */
|
|
||||||
void lock_upgrade(const index_lock &lock);
|
|
||||||
|
|
||||||
/** Check if we are holding tablespace latch
|
/** Check if we are holding tablespace latch
|
||||||
@param space tablespace to search for
|
@param space tablespace to search for
|
||||||
@@ -454,31 +381,66 @@ public:
|
|||||||
@retval nullptr if not found */
|
@retval nullptr if not found */
|
||||||
buf_block_t *memo_contains_page_flagged(const byte *ptr, ulint flags) const;
|
buf_block_t *memo_contains_page_flagged(const byte *ptr, ulint flags) const;
|
||||||
|
|
||||||
/** @return true if mini-transaction contains modifications. */
|
/** @return whether this mini-transaction modifies persistent data */
|
||||||
bool has_modifications() const { return m_modifications; }
|
bool has_modifications() const { return m_modifications; }
|
||||||
#endif /* UNIV_DEBUG */
|
#endif /* UNIV_DEBUG */
|
||||||
|
|
||||||
/** Push an object to an mtr memo stack.
|
/** Push a buffer page to an the memo.
|
||||||
@param object object
|
@param block buffer block
|
||||||
|
@param type object type: MTR_MEMO_S_LOCK, ... */
|
||||||
|
void memo_push(buf_block_t *block, mtr_memo_type_t type)
|
||||||
|
__attribute__((nonnull))
|
||||||
|
{
|
||||||
|
ut_ad(is_active());
|
||||||
|
ut_ad(type <= MTR_MEMO_PAGE_SX_MODIFY);
|
||||||
|
ut_ad(block->page.buf_fix_count());
|
||||||
|
ut_ad(block->page.in_file());
|
||||||
|
#ifdef UNIV_DEBUG
|
||||||
|
switch (type) {
|
||||||
|
case MTR_MEMO_PAGE_S_FIX:
|
||||||
|
ut_ad(block->page.lock.have_s());
|
||||||
|
break;
|
||||||
|
case MTR_MEMO_PAGE_X_FIX: case MTR_MEMO_PAGE_X_MODIFY:
|
||||||
|
ut_ad(block->page.lock.have_x());
|
||||||
|
break;
|
||||||
|
case MTR_MEMO_PAGE_SX_FIX: case MTR_MEMO_PAGE_SX_MODIFY:
|
||||||
|
ut_ad(block->page.lock.have_u_or_x());
|
||||||
|
break;
|
||||||
|
case MTR_MEMO_BUF_FIX:
|
||||||
|
break;
|
||||||
|
case MTR_MEMO_MODIFY:
|
||||||
|
case MTR_MEMO_S_LOCK: case MTR_MEMO_X_LOCK: case MTR_MEMO_SX_LOCK:
|
||||||
|
case MTR_MEMO_SPACE_X_LOCK: case MTR_MEMO_SPACE_S_LOCK:
|
||||||
|
ut_ad("invalid type" == 0);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (!(type & MTR_MEMO_MODIFY));
|
||||||
|
else if (block->page.id().space() >= SRV_TMP_SPACE_ID)
|
||||||
|
{
|
||||||
|
block->page.set_temp_modified();
|
||||||
|
type= mtr_memo_type_t(type & ~MTR_MEMO_MODIFY);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_modifications= true;
|
||||||
|
if (!m_made_dirty)
|
||||||
|
/* If we are going to modify a previously clean persistent page,
|
||||||
|
we must set m_made_dirty, so that commit() will acquire
|
||||||
|
log_sys.flush_order_mutex and insert the block into
|
||||||
|
buf_pool.flush_list. */
|
||||||
|
m_made_dirty= block->page.oldest_modification() <= 1;
|
||||||
|
}
|
||||||
|
m_memo.emplace_back(mtr_memo_slot_t{block, type});
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Push an index lock or tablespace latch to the memo.
|
||||||
|
@param object index lock or tablespace latch
|
||||||
@param type object type: MTR_MEMO_S_LOCK, ... */
|
@param type object type: MTR_MEMO_S_LOCK, ... */
|
||||||
void memo_push(void *object, mtr_memo_type_t type) __attribute__((nonnull))
|
void memo_push(void *object, mtr_memo_type_t type) __attribute__((nonnull))
|
||||||
{
|
{
|
||||||
ut_ad(is_active());
|
ut_ad(is_active());
|
||||||
/* If this mtr has U or X latched a clean page then we set
|
ut_ad(type >= MTR_MEMO_S_LOCK);
|
||||||
the m_made_dirty flag. This tells us if we need to
|
m_memo.emplace_back(mtr_memo_slot_t{object, type});
|
||||||
grab log_sys.flush_order_mutex at mtr_t::commit() so that we
|
|
||||||
can insert the dirtied page into the buf_pool.flush_list.
|
|
||||||
|
|
||||||
FIXME: Do this only when the MTR_MEMO_MODIFY flag is set! */
|
|
||||||
if (!m_made_dirty &&
|
|
||||||
(type & (MTR_MEMO_PAGE_X_FIX | MTR_MEMO_PAGE_SX_FIX)))
|
|
||||||
m_made_dirty=
|
|
||||||
is_block_dirtied(*static_cast<const buf_page_t*>(object));
|
|
||||||
|
|
||||||
if (!m_memo)
|
|
||||||
m_memo= new std::vector<mtr_memo_slot_t>(1, {object, type});
|
|
||||||
else
|
|
||||||
m_memo->emplace_back(mtr_memo_slot_t{object, type});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return the size of the log is empty */
|
/** @return the size of the log is empty */
|
||||||
@@ -783,7 +745,7 @@ private:
|
|||||||
/** specifies which operations should be logged; default MTR_LOG_ALL */
|
/** specifies which operations should be logged; default MTR_LOG_ALL */
|
||||||
uint16_t m_log_mode:2;
|
uint16_t m_log_mode:2;
|
||||||
|
|
||||||
/** whether at least one buffer pool page was written to */
|
/** whether at least one persistent page was written to */
|
||||||
uint16_t m_modifications:1;
|
uint16_t m_modifications:1;
|
||||||
|
|
||||||
/** whether at least one previously clean buffer pool page was written to */
|
/** whether at least one previously clean buffer pool page was written to */
|
||||||
@@ -809,7 +771,7 @@ private:
|
|||||||
#endif /* UNIV_DEBUG */
|
#endif /* UNIV_DEBUG */
|
||||||
|
|
||||||
/** acquired dict_index_t::lock, fil_space_t::latch, buf_block_t */
|
/** acquired dict_index_t::lock, fil_space_t::latch, buf_block_t */
|
||||||
std::vector<mtr_memo_slot_t> *m_memo= nullptr;
|
small_vector<mtr_memo_slot_t, 16> m_memo;
|
||||||
|
|
||||||
/** mini-transaction log */
|
/** mini-transaction log */
|
||||||
mtr_buf_t m_log;
|
mtr_buf_t m_log;
|
||||||
|
100
storage/innobase/include/small_vector.h
Normal file
100
storage/innobase/include/small_vector.h
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
|
||||||
|
Copyright (c) 2023, MariaDB Corporation.
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify it under
|
||||||
|
the terms of the GNU General Public License as published by the Free Software
|
||||||
|
Foundation; version 2 of the License.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License along with
|
||||||
|
this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA
|
||||||
|
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
/* A normally small vector, inspired by llvm::SmallVector */
|
||||||
|
#include "my_global.h"
|
||||||
|
#include <iterator>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
class small_vector_base
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
typedef uint32_t Size_T;
|
||||||
|
void *BeginX;
|
||||||
|
Size_T Size= 0, Capacity;
|
||||||
|
small_vector_base()= delete;
|
||||||
|
small_vector_base(void *small, size_t small_size)
|
||||||
|
: BeginX(small), Capacity(Size_T(small_size)) {}
|
||||||
|
ATTRIBUTE_COLD void grow_by_1(void *small, size_t element_size);
|
||||||
|
public:
|
||||||
|
size_t size() const { return Size; }
|
||||||
|
size_t capacity() const { return Capacity; }
|
||||||
|
bool empty() const { return !Size; }
|
||||||
|
void clear() { Size= 0; }
|
||||||
|
protected:
|
||||||
|
void set_size(size_t N) { Size= Size_T(N); }
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T, unsigned N>
|
||||||
|
class small_vector : public small_vector_base
|
||||||
|
{
|
||||||
|
/** The fixed storage allocation */
|
||||||
|
T small[N];
|
||||||
|
|
||||||
|
using small_vector_base::set_size;
|
||||||
|
|
||||||
|
void grow_if_needed()
|
||||||
|
{
|
||||||
|
if (unlikely(size() >= capacity()))
|
||||||
|
grow_by_1(small, sizeof *small);
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
small_vector() : small_vector_base(small, N)
|
||||||
|
{
|
||||||
|
TRASH_ALLOC(small, sizeof small);
|
||||||
|
}
|
||||||
|
~small_vector()
|
||||||
|
{
|
||||||
|
if (small != begin())
|
||||||
|
my_free(begin());
|
||||||
|
MEM_MAKE_ADDRESSABLE(small, sizeof small);
|
||||||
|
}
|
||||||
|
|
||||||
|
using iterator= T *;
|
||||||
|
using const_iterator= const T *;
|
||||||
|
using reverse_iterator= std::reverse_iterator<iterator>;
|
||||||
|
using reference= T &;
|
||||||
|
using const_reference= const T&;
|
||||||
|
|
||||||
|
iterator begin() { return static_cast<iterator>(BeginX); }
|
||||||
|
const_iterator begin() const { return static_cast<const_iterator>(BeginX); }
|
||||||
|
iterator end() { return begin() + size(); }
|
||||||
|
const_iterator end() const { return begin() + size(); }
|
||||||
|
|
||||||
|
reverse_iterator rbegin() { return reverse_iterator(end()); }
|
||||||
|
reverse_iterator rend() { return reverse_iterator(begin()); }
|
||||||
|
|
||||||
|
reference operator[](size_t i) { assert(i < size()); return begin()[i]; }
|
||||||
|
const_reference operator[](size_t i) const
|
||||||
|
{ return const_cast<small_vector&>(*this)[i]; }
|
||||||
|
|
||||||
|
void erase(const_iterator S, const_iterator E)
|
||||||
|
{
|
||||||
|
set_size(std::move(const_cast<iterator>(E), end(),
|
||||||
|
const_cast<iterator>(S)) - begin());
|
||||||
|
}
|
||||||
|
|
||||||
|
void emplace_back(T &&arg)
|
||||||
|
{
|
||||||
|
grow_if_needed();
|
||||||
|
::new (end()) T(arg);
|
||||||
|
set_size(size() + 1);
|
||||||
|
}
|
||||||
|
};
|
@@ -1,7 +1,7 @@
|
|||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
|
|
||||||
Copyright (c) 1995, 2017, Oracle and/or its affiliates. All Rights Reserved.
|
Copyright (c) 1995, 2017, Oracle and/or its affiliates. All Rights Reserved.
|
||||||
Copyright (c) 2017, 2022, MariaDB Corporation.
|
Copyright (c) 2017, 2023, MariaDB Corporation.
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify it under
|
This program is free software; you can redistribute it and/or modify it under
|
||||||
the terms of the GNU General Public License as published by the Free Software
|
the terms of the GNU General Public License as published by the Free Software
|
||||||
@@ -37,6 +37,8 @@ Created 11/26/1995 Heikki Tuuri
|
|||||||
|
|
||||||
void mtr_memo_slot_t::release() const
|
void mtr_memo_slot_t::release() const
|
||||||
{
|
{
|
||||||
|
ut_ad(object);
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case MTR_MEMO_S_LOCK:
|
case MTR_MEMO_S_LOCK:
|
||||||
static_cast<index_lock*>(object)->s_unlock();
|
static_cast<index_lock*>(object)->s_unlock();
|
||||||
@@ -153,10 +155,13 @@ inline void buf_pool_t::insert_into_flush_list(buf_page_t *prev,
|
|||||||
block->page.set_oldest_modification(lsn);
|
block->page.set_oldest_modification(lsn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mtr_t::mtr_t()= default;
|
||||||
|
mtr_t::~mtr_t()= default;
|
||||||
|
|
||||||
/** Start a mini-transaction. */
|
/** Start a mini-transaction. */
|
||||||
void mtr_t::start()
|
void mtr_t::start()
|
||||||
{
|
{
|
||||||
ut_ad(!m_memo);
|
ut_ad(m_memo.empty());
|
||||||
ut_ad(!m_freed_pages);
|
ut_ad(!m_freed_pages);
|
||||||
ut_ad(!m_freed_space);
|
ut_ad(!m_freed_space);
|
||||||
MEM_UNDEFINED(this, sizeof *this);
|
MEM_UNDEFINED(this, sizeof *this);
|
||||||
@@ -188,7 +193,7 @@ void mtr_t::start()
|
|||||||
inline void mtr_t::release_resources()
|
inline void mtr_t::release_resources()
|
||||||
{
|
{
|
||||||
ut_ad(is_active());
|
ut_ad(is_active());
|
||||||
ut_ad(!m_memo);
|
ut_ad(m_memo.empty());
|
||||||
m_log.erase();
|
m_log.erase();
|
||||||
ut_d(m_commit= true);
|
ut_d(m_commit= true);
|
||||||
}
|
}
|
||||||
@@ -243,15 +248,13 @@ void mtr_t::release_unlogged()
|
|||||||
{
|
{
|
||||||
ut_ad(m_log_mode == MTR_LOG_NO_REDO);
|
ut_ad(m_log_mode == MTR_LOG_NO_REDO);
|
||||||
ut_ad(m_log.size() == 0);
|
ut_ad(m_log.size() == 0);
|
||||||
ut_ad(m_memo);
|
|
||||||
|
|
||||||
process_freed_pages();
|
process_freed_pages();
|
||||||
|
|
||||||
for (auto it= m_memo->rbegin(); it != m_memo->rend(); it++)
|
for (auto it= m_memo.rbegin(); it != m_memo.rend(); it++)
|
||||||
{
|
{
|
||||||
mtr_memo_slot_t &slot= *it;
|
mtr_memo_slot_t &slot= *it;
|
||||||
if (!slot.object)
|
ut_ad(slot.object);
|
||||||
continue;
|
|
||||||
switch (slot.type) {
|
switch (slot.type) {
|
||||||
case MTR_MEMO_S_LOCK:
|
case MTR_MEMO_S_LOCK:
|
||||||
static_cast<index_lock*>(slot.object)->s_unlock();
|
static_cast<index_lock*>(slot.object)->s_unlock();
|
||||||
@@ -278,10 +281,8 @@ void mtr_t::release_unlogged()
|
|||||||
{
|
{
|
||||||
ut_ad(slot.type == MTR_MEMO_PAGE_X_MODIFY ||
|
ut_ad(slot.type == MTR_MEMO_PAGE_X_MODIFY ||
|
||||||
slot.type == MTR_MEMO_PAGE_SX_MODIFY);
|
slot.type == MTR_MEMO_PAGE_SX_MODIFY);
|
||||||
if (UNIV_LIKELY(block->page.id() >= end_page_id))
|
ut_ad(block->page.id() < end_page_id);
|
||||||
block->page.set_temp_modified();
|
insert_imported(block);
|
||||||
else
|
|
||||||
insert_imported(block);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (slot.type) {
|
switch (slot.type) {
|
||||||
@@ -300,23 +301,14 @@ void mtr_t::release_unlogged()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
delete m_memo;
|
m_memo.clear();
|
||||||
m_memo= nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void mtr_t::release()
|
void mtr_t::release()
|
||||||
{
|
{
|
||||||
if (m_memo)
|
for (auto it= m_memo.rbegin(); it != m_memo.rend(); it++)
|
||||||
{
|
it->release();
|
||||||
for (auto it= m_memo->rbegin(); it != m_memo->rend(); it++)
|
m_memo.clear();
|
||||||
{
|
|
||||||
mtr_memo_slot_t &slot= *it;
|
|
||||||
if (slot.object)
|
|
||||||
slot.release();
|
|
||||||
}
|
|
||||||
delete m_memo;
|
|
||||||
m_memo= nullptr;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Commit a mini-transaction. */
|
/** Commit a mini-transaction. */
|
||||||
@@ -344,19 +336,18 @@ void mtr_t::commit()
|
|||||||
|
|
||||||
if (m_made_dirty)
|
if (m_made_dirty)
|
||||||
{
|
{
|
||||||
ut_ad(m_memo);
|
|
||||||
size_t modified= 0;
|
size_t modified= 0;
|
||||||
auto it= m_memo->rbegin();
|
auto it= m_memo.rbegin();
|
||||||
|
|
||||||
mysql_mutex_lock(&buf_pool.flush_list_mutex);
|
mysql_mutex_lock(&buf_pool.flush_list_mutex);
|
||||||
|
|
||||||
buf_page_t *const prev=
|
buf_page_t *const prev=
|
||||||
buf_pool.prepare_insert_into_flush_list(lsns.first);
|
buf_pool.prepare_insert_into_flush_list(lsns.first);
|
||||||
|
|
||||||
while (it != m_memo->rend())
|
while (it != m_memo.rend())
|
||||||
{
|
{
|
||||||
const mtr_memo_slot_t &slot= *it++;
|
const mtr_memo_slot_t &slot= *it++;
|
||||||
if (slot.object && slot.type & MTR_MEMO_MODIFY)
|
if (slot.type & MTR_MEMO_MODIFY)
|
||||||
{
|
{
|
||||||
ut_ad(slot.type == MTR_MEMO_PAGE_X_MODIFY ||
|
ut_ad(slot.type == MTR_MEMO_PAGE_X_MODIFY ||
|
||||||
slot.type == MTR_MEMO_PAGE_SX_MODIFY);
|
slot.type == MTR_MEMO_PAGE_SX_MODIFY);
|
||||||
@@ -401,72 +392,67 @@ void mtr_t::commit()
|
|||||||
else
|
else
|
||||||
log_sys.latch.rd_unlock();
|
log_sys.latch.rd_unlock();
|
||||||
|
|
||||||
if (m_memo)
|
size_t modified= 0;
|
||||||
{
|
|
||||||
size_t modified= 0;
|
|
||||||
|
|
||||||
for (auto it= m_memo->rbegin(); it != m_memo->rend(); )
|
for (auto it= m_memo.rbegin(); it != m_memo.rend(); )
|
||||||
{
|
{
|
||||||
const mtr_memo_slot_t &slot= *it++;
|
const mtr_memo_slot_t &slot= *it++;
|
||||||
if (!slot.object)
|
ut_ad(slot.object);
|
||||||
continue;
|
switch (slot.type) {
|
||||||
switch (slot.type) {
|
case MTR_MEMO_S_LOCK:
|
||||||
case MTR_MEMO_S_LOCK:
|
static_cast<index_lock*>(slot.object)->s_unlock();
|
||||||
static_cast<index_lock*>(slot.object)->s_unlock();
|
break;
|
||||||
break;
|
case MTR_MEMO_SPACE_X_LOCK:
|
||||||
case MTR_MEMO_SPACE_X_LOCK:
|
static_cast<fil_space_t*>(slot.object)->set_committed_size();
|
||||||
static_cast<fil_space_t*>(slot.object)->set_committed_size();
|
static_cast<fil_space_t*>(slot.object)->x_unlock();
|
||||||
static_cast<fil_space_t*>(slot.object)->x_unlock();
|
break;
|
||||||
break;
|
case MTR_MEMO_SPACE_S_LOCK:
|
||||||
case MTR_MEMO_SPACE_S_LOCK:
|
static_cast<fil_space_t*>(slot.object)->s_unlock();
|
||||||
static_cast<fil_space_t*>(slot.object)->s_unlock();
|
break;
|
||||||
break;
|
case MTR_MEMO_X_LOCK:
|
||||||
case MTR_MEMO_X_LOCK:
|
case MTR_MEMO_SX_LOCK:
|
||||||
case MTR_MEMO_SX_LOCK:
|
static_cast<index_lock*>(slot.object)->
|
||||||
static_cast<index_lock*>(slot.object)->
|
u_or_x_unlock(slot.type == MTR_MEMO_SX_LOCK);
|
||||||
u_or_x_unlock(slot.type == MTR_MEMO_SX_LOCK);
|
break;
|
||||||
break;
|
default:
|
||||||
default:
|
buf_page_t *bpage= static_cast<buf_page_t*>(slot.object);
|
||||||
buf_page_t *bpage= static_cast<buf_page_t*>(slot.object);
|
const auto s= bpage->unfix();
|
||||||
const auto s= bpage->unfix();
|
if (slot.type & MTR_MEMO_MODIFY)
|
||||||
if (slot.type & MTR_MEMO_MODIFY)
|
{
|
||||||
|
ut_ad(slot.type == MTR_MEMO_PAGE_X_MODIFY ||
|
||||||
|
slot.type == MTR_MEMO_PAGE_SX_MODIFY);
|
||||||
|
ut_ad(bpage->oldest_modification() > 1);
|
||||||
|
ut_ad(bpage->oldest_modification() < m_commit_lsn);
|
||||||
|
ut_ad(bpage->id() < end_page_id);
|
||||||
|
ut_ad(s >= buf_page_t::FREED);
|
||||||
|
ut_ad(s < buf_page_t::READ_FIX);
|
||||||
|
ut_ad(mach_read_from_8(bpage->frame + FIL_PAGE_LSN) <=
|
||||||
|
m_commit_lsn);
|
||||||
|
if (s >= buf_page_t::UNFIXED)
|
||||||
{
|
{
|
||||||
ut_ad(slot.type == MTR_MEMO_PAGE_X_MODIFY ||
|
mach_write_to_8(bpage->frame + FIL_PAGE_LSN, m_commit_lsn);
|
||||||
slot.type == MTR_MEMO_PAGE_SX_MODIFY);
|
if (UNIV_LIKELY_NULL(bpage->zip.data))
|
||||||
ut_ad(bpage->oldest_modification() > 1);
|
memcpy_aligned<8>(FIL_PAGE_LSN + bpage->zip.data,
|
||||||
ut_ad(bpage->oldest_modification() < m_commit_lsn);
|
FIL_PAGE_LSN + bpage->frame, 8);
|
||||||
ut_ad(bpage->id() < end_page_id);
|
|
||||||
ut_ad(s >= buf_page_t::FREED);
|
|
||||||
ut_ad(s < buf_page_t::READ_FIX);
|
|
||||||
ut_ad(mach_read_from_8(bpage->frame + FIL_PAGE_LSN) <=
|
|
||||||
m_commit_lsn);
|
|
||||||
if (s >= buf_page_t::UNFIXED)
|
|
||||||
{
|
|
||||||
mach_write_to_8(bpage->frame + FIL_PAGE_LSN, m_commit_lsn);
|
|
||||||
if (UNIV_LIKELY_NULL(bpage->zip.data))
|
|
||||||
memcpy_aligned<8>(FIL_PAGE_LSN + bpage->zip.data,
|
|
||||||
FIL_PAGE_LSN + bpage->frame, 8);
|
|
||||||
}
|
|
||||||
modified++;
|
|
||||||
}
|
|
||||||
switch (auto latch= slot.type & ~MTR_MEMO_MODIFY) {
|
|
||||||
case MTR_MEMO_PAGE_S_FIX:
|
|
||||||
bpage->lock.s_unlock();
|
|
||||||
continue;
|
|
||||||
case MTR_MEMO_PAGE_SX_FIX:
|
|
||||||
case MTR_MEMO_PAGE_X_FIX:
|
|
||||||
bpage->lock.u_or_x_unlock(latch == MTR_MEMO_PAGE_SX_FIX);
|
|
||||||
continue;
|
|
||||||
default:
|
|
||||||
ut_ad(latch == MTR_MEMO_BUF_FIX);
|
|
||||||
}
|
}
|
||||||
|
modified++;
|
||||||
|
}
|
||||||
|
switch (auto latch= slot.type & ~MTR_MEMO_MODIFY) {
|
||||||
|
case MTR_MEMO_PAGE_S_FIX:
|
||||||
|
bpage->lock.s_unlock();
|
||||||
|
continue;
|
||||||
|
case MTR_MEMO_PAGE_SX_FIX:
|
||||||
|
case MTR_MEMO_PAGE_X_FIX:
|
||||||
|
bpage->lock.u_or_x_unlock(latch == MTR_MEMO_PAGE_SX_FIX);
|
||||||
|
continue;
|
||||||
|
default:
|
||||||
|
ut_ad(latch == MTR_MEMO_BUF_FIX);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
buf_pool.add_flush_list_requests(modified);
|
|
||||||
delete m_memo;
|
|
||||||
m_memo= nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
buf_pool.add_flush_list_requests(modified);
|
||||||
|
m_memo.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (UNIV_UNLIKELY(lsns.second != PAGE_FLUSH_NO))
|
if (UNIV_UNLIKELY(lsns.second != PAGE_FLUSH_NO))
|
||||||
@@ -481,16 +467,14 @@ func_exit:
|
|||||||
|
|
||||||
void mtr_t::rollback_to_savepoint(ulint begin, ulint end)
|
void mtr_t::rollback_to_savepoint(ulint begin, ulint end)
|
||||||
{
|
{
|
||||||
ut_ad(m_memo);
|
ut_ad(end <= m_memo.size());
|
||||||
ut_ad(end <= m_memo->size());
|
|
||||||
ut_ad(begin <= end);
|
ut_ad(begin <= end);
|
||||||
ulint s= end;
|
ulint s= end;
|
||||||
|
|
||||||
while (s-- > begin)
|
while (s-- > begin)
|
||||||
{
|
{
|
||||||
const mtr_memo_slot_t &slot= (*m_memo)[s];
|
const mtr_memo_slot_t &slot= m_memo[s];
|
||||||
if (!slot.object)
|
ut_ad(slot.object);
|
||||||
continue;
|
|
||||||
/* This is intended for releasing latches on indexes or unmodified
|
/* This is intended for releasing latches on indexes or unmodified
|
||||||
buffer pool pages. */
|
buffer pool pages. */
|
||||||
ut_ad(slot.type <= MTR_MEMO_SX_LOCK);
|
ut_ad(slot.type <= MTR_MEMO_SX_LOCK);
|
||||||
@@ -498,7 +482,7 @@ void mtr_t::rollback_to_savepoint(ulint begin, ulint end)
|
|||||||
slot.release();
|
slot.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
m_memo->erase(m_memo->begin() + begin, m_memo->begin() + end);
|
m_memo.erase(m_memo.begin() + begin, m_memo.begin() + end);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Commit a mini-transaction that is shrinking a tablespace.
|
/** Commit a mini-transaction that is shrinking a tablespace.
|
||||||
@@ -510,9 +494,10 @@ void mtr_t::commit_shrink(fil_space_t &space)
|
|||||||
ut_ad(!high_level_read_only);
|
ut_ad(!high_level_read_only);
|
||||||
ut_ad(m_modifications);
|
ut_ad(m_modifications);
|
||||||
ut_ad(m_made_dirty);
|
ut_ad(m_made_dirty);
|
||||||
ut_ad(m_memo);
|
ut_ad(!m_memo.empty());
|
||||||
ut_ad(!recv_recovery_is_on());
|
ut_ad(!recv_recovery_is_on());
|
||||||
ut_ad(m_log_mode == MTR_LOG_ALL);
|
ut_ad(m_log_mode == MTR_LOG_ALL);
|
||||||
|
ut_ad(!m_freed_pages);
|
||||||
ut_ad(UT_LIST_GET_LEN(space.chain) == 1);
|
ut_ad(UT_LIST_GET_LEN(space.chain) == 1);
|
||||||
|
|
||||||
log_write_and_flush_prepare();
|
log_write_and_flush_prepare();
|
||||||
@@ -531,22 +516,21 @@ void mtr_t::commit_shrink(fil_space_t &space)
|
|||||||
os_file_truncate(space.chain.start->name, space.chain.start->handle,
|
os_file_truncate(space.chain.start->name, space.chain.start->handle,
|
||||||
os_offset_t{space.size} << srv_page_size_shift, true);
|
os_offset_t{space.size} << srv_page_size_shift, true);
|
||||||
|
|
||||||
ut_ad(!m_freed_pages || m_freed_space == &space);
|
space.clear_freed_ranges();
|
||||||
process_freed_pages();
|
|
||||||
|
|
||||||
const page_id_t high{space.id, space.size};
|
const page_id_t high{space.id, space.size};
|
||||||
size_t modified= 0;
|
size_t modified= 0;
|
||||||
auto it= m_memo->rbegin();
|
auto it= m_memo.rbegin();
|
||||||
mysql_mutex_lock(&buf_pool.flush_list_mutex);
|
mysql_mutex_lock(&buf_pool.flush_list_mutex);
|
||||||
|
|
||||||
buf_page_t *const prev= buf_pool.prepare_insert_into_flush_list(start_lsn);
|
buf_page_t *const prev= buf_pool.prepare_insert_into_flush_list(start_lsn);
|
||||||
|
|
||||||
while (it != m_memo->rend())
|
while (it != m_memo.rend())
|
||||||
{
|
{
|
||||||
mtr_memo_slot_t &slot= *it++;
|
mtr_memo_slot_t &slot= *it++;
|
||||||
|
|
||||||
if (!slot.object);
|
ut_ad(slot.object);
|
||||||
else if (slot.type == MTR_MEMO_SPACE_X_LOCK)
|
if (slot.type == MTR_MEMO_SPACE_X_LOCK)
|
||||||
ut_ad(high.space() == static_cast<fil_space_t*>(slot.object)->id);
|
ut_ad(high.space() == static_cast<fil_space_t*>(slot.object)->id);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -727,7 +711,7 @@ lsn_t mtr_t::commit_files(lsn_t checkpoint_lsn)
|
|||||||
ut_ad(!is_inside_ibuf());
|
ut_ad(!is_inside_ibuf());
|
||||||
ut_ad(m_log_mode == MTR_LOG_ALL);
|
ut_ad(m_log_mode == MTR_LOG_ALL);
|
||||||
ut_ad(!m_made_dirty);
|
ut_ad(!m_made_dirty);
|
||||||
ut_ad(!m_memo);
|
ut_ad(m_memo.empty());
|
||||||
ut_ad(!srv_read_only_mode);
|
ut_ad(!srv_read_only_mode);
|
||||||
ut_ad(!m_freed_space);
|
ut_ad(!m_freed_space);
|
||||||
ut_ad(!m_freed_pages);
|
ut_ad(!m_freed_pages);
|
||||||
@@ -837,19 +821,18 @@ void mtr_t::x_lock_space(fil_space_t *space)
|
|||||||
void mtr_t::release(const void *object)
|
void mtr_t::release(const void *object)
|
||||||
{
|
{
|
||||||
ut_ad(is_active());
|
ut_ad(is_active());
|
||||||
ut_ad(m_memo);
|
|
||||||
|
|
||||||
auto it=
|
auto it=
|
||||||
std::find_if(m_memo->begin(), m_memo->end(),
|
std::find_if(m_memo.begin(), m_memo.end(),
|
||||||
[object](const mtr_memo_slot_t& slot)
|
[object](const mtr_memo_slot_t& slot)
|
||||||
{ return slot.object == object; });
|
{ return slot.object == object; });
|
||||||
ut_ad(it != m_memo->end());
|
ut_ad(it != m_memo.end());
|
||||||
ut_ad(!(it->type & MTR_MEMO_MODIFY));
|
ut_ad(!(it->type & MTR_MEMO_MODIFY));
|
||||||
it->release();
|
it->release();
|
||||||
m_memo->erase(it);
|
m_memo.erase(it, it + 1);
|
||||||
ut_ad(std::find_if(m_memo->begin(), m_memo->end(),
|
ut_ad(std::find_if(m_memo.begin(), m_memo.end(),
|
||||||
[object](const mtr_memo_slot_t& slot)
|
[object](const mtr_memo_slot_t& slot)
|
||||||
{ return slot.object == &object; }) == m_memo->end());
|
{ return slot.object == &object; }) == m_memo.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
static time_t log_close_warn_time;
|
static time_t log_close_warn_time;
|
||||||
@@ -1028,11 +1011,11 @@ std::pair<lsn_t,mtr_t::page_flush_ahead> mtr_t::do_write()
|
|||||||
#ifndef DBUG_OFF
|
#ifndef DBUG_OFF
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
if (!m_memo || m_log_mode != MTR_LOG_ALL)
|
if (m_log_mode != MTR_LOG_ALL)
|
||||||
continue;
|
continue;
|
||||||
DBUG_EXECUTE_IF("skip_page_checksum", continue;);
|
DBUG_EXECUTE_IF("skip_page_checksum", continue;);
|
||||||
|
|
||||||
for (const mtr_memo_slot_t& slot : *m_memo)
|
for (const mtr_memo_slot_t& slot : m_memo)
|
||||||
if (slot.type & MTR_MEMO_MODIFY)
|
if (slot.type & MTR_MEMO_MODIFY)
|
||||||
{
|
{
|
||||||
const buf_page_t &b= *static_cast<const buf_page_t*>(slot.object);
|
const buf_page_t &b= *static_cast<const buf_page_t*>(slot.object);
|
||||||
@@ -1284,12 +1267,9 @@ mtr_t::finish_write(size_t len)
|
|||||||
|
|
||||||
bool mtr_t::have_x_latch(const buf_block_t &block) const
|
bool mtr_t::have_x_latch(const buf_block_t &block) const
|
||||||
{
|
{
|
||||||
if (!m_memo)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
ut_d(const mtr_memo_slot_t *found= nullptr);
|
ut_d(const mtr_memo_slot_t *found= nullptr);
|
||||||
|
|
||||||
for (const mtr_memo_slot_t &slot : *m_memo)
|
for (const mtr_memo_slot_t &slot : m_memo)
|
||||||
{
|
{
|
||||||
if (slot.object != &block)
|
if (slot.object != &block)
|
||||||
continue;
|
continue;
|
||||||
@@ -1309,16 +1289,13 @@ bool mtr_t::have_x_latch(const buf_block_t &block) const
|
|||||||
|
|
||||||
bool mtr_t::have_u_or_x_latch(const buf_block_t &block) const
|
bool mtr_t::have_u_or_x_latch(const buf_block_t &block) const
|
||||||
{
|
{
|
||||||
if (m_memo)
|
for (const mtr_memo_slot_t &slot : m_memo)
|
||||||
{
|
{
|
||||||
for (const mtr_memo_slot_t &slot : *m_memo)
|
if (slot.object == &block &&
|
||||||
|
slot.type & (MTR_MEMO_PAGE_X_FIX | MTR_MEMO_PAGE_SX_FIX))
|
||||||
{
|
{
|
||||||
if (slot.object == &block &&
|
ut_ad(block.page.lock.have_u_or_x());
|
||||||
slot.type & (MTR_MEMO_PAGE_X_FIX | MTR_MEMO_PAGE_SX_FIX))
|
return true;
|
||||||
{
|
|
||||||
ut_ad(block.page.lock.have_u_or_x());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@@ -1330,18 +1307,15 @@ bool mtr_t::have_u_or_x_latch(const buf_block_t &block) const
|
|||||||
@return whether space.latch is being held */
|
@return whether space.latch is being held */
|
||||||
bool mtr_t::memo_contains(const fil_space_t& space, bool shared) const
|
bool mtr_t::memo_contains(const fil_space_t& space, bool shared) const
|
||||||
{
|
{
|
||||||
if (m_memo)
|
const mtr_memo_type_t type= shared
|
||||||
{
|
? MTR_MEMO_SPACE_S_LOCK : MTR_MEMO_SPACE_X_LOCK;
|
||||||
const mtr_memo_type_t type= shared
|
|
||||||
? MTR_MEMO_SPACE_S_LOCK : MTR_MEMO_SPACE_X_LOCK;
|
|
||||||
|
|
||||||
for (const mtr_memo_slot_t &slot : *m_memo)
|
for (const mtr_memo_slot_t &slot : m_memo)
|
||||||
|
{
|
||||||
|
if (slot.object == &space && slot.type == type)
|
||||||
{
|
{
|
||||||
if (slot.object == &space && slot.type == type)
|
ut_ad(shared || space.is_owner());
|
||||||
{
|
return true;
|
||||||
ut_ad(shared || space.is_owner());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1351,9 +1325,8 @@ bool mtr_t::memo_contains(const fil_space_t& space, bool shared) const
|
|||||||
void mtr_t::page_lock_upgrade(const buf_block_t &block)
|
void mtr_t::page_lock_upgrade(const buf_block_t &block)
|
||||||
{
|
{
|
||||||
ut_ad(block.page.lock.have_x());
|
ut_ad(block.page.lock.have_x());
|
||||||
ut_ad(m_memo);
|
|
||||||
|
|
||||||
for (mtr_memo_slot_t &slot : *m_memo)
|
for (mtr_memo_slot_t &slot : m_memo)
|
||||||
if (slot.object == &block && slot.type & MTR_MEMO_PAGE_SX_FIX)
|
if (slot.object == &block && slot.type & MTR_MEMO_PAGE_SX_FIX)
|
||||||
slot.type= mtr_memo_type_t(slot.type ^
|
slot.type= mtr_memo_type_t(slot.type ^
|
||||||
(MTR_MEMO_PAGE_SX_FIX | MTR_MEMO_PAGE_X_FIX));
|
(MTR_MEMO_PAGE_SX_FIX | MTR_MEMO_PAGE_X_FIX));
|
||||||
@@ -1363,16 +1336,6 @@ void mtr_t::page_lock_upgrade(const buf_block_t &block)
|
|||||||
#endif /* BTR_CUR_HASH_ADAPT */
|
#endif /* BTR_CUR_HASH_ADAPT */
|
||||||
}
|
}
|
||||||
|
|
||||||
void mtr_t::lock_upgrade(const index_lock &lock)
|
|
||||||
{
|
|
||||||
ut_ad(lock.have_x());
|
|
||||||
ut_ad(m_memo);
|
|
||||||
|
|
||||||
for (mtr_memo_slot_t &slot : *m_memo)
|
|
||||||
if (slot.object == &lock && slot.type == MTR_MEMO_SX_LOCK)
|
|
||||||
slot.type= MTR_MEMO_X_LOCK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Latch a buffer pool block.
|
/** Latch a buffer pool block.
|
||||||
@param block block to be latched
|
@param block block to be latched
|
||||||
@param rw_latch RW_S_LATCH, RW_SX_LATCH, RW_X_LATCH, RW_NO_LATCH */
|
@param rw_latch RW_S_LATCH, RW_SX_LATCH, RW_X_LATCH, RW_NO_LATCH */
|
||||||
@@ -1421,27 +1384,29 @@ done:
|
|||||||
void mtr_t::upgrade_buffer_fix(ulint savepoint, rw_lock_type_t rw_latch)
|
void mtr_t::upgrade_buffer_fix(ulint savepoint, rw_lock_type_t rw_latch)
|
||||||
{
|
{
|
||||||
ut_ad(is_active());
|
ut_ad(is_active());
|
||||||
ut_ad(m_memo);
|
mtr_memo_slot_t &slot= m_memo[savepoint];
|
||||||
ut_ad(savepoint < m_memo->size());
|
|
||||||
|
|
||||||
mtr_memo_slot_t &slot= (*m_memo)[savepoint];
|
|
||||||
ut_ad(slot.type == MTR_MEMO_BUF_FIX);
|
ut_ad(slot.type == MTR_MEMO_BUF_FIX);
|
||||||
buf_block_t *block= static_cast<buf_block_t*>(slot.object);
|
buf_block_t *block= static_cast<buf_block_t*>(slot.object);
|
||||||
ut_d(const auto state= block->page.state());
|
ut_d(const auto state= block->page.state());
|
||||||
ut_ad(state > buf_page_t::UNFIXED);
|
ut_ad(state > buf_page_t::UNFIXED);
|
||||||
ut_ad(state > buf_page_t::WRITE_FIX || state < buf_page_t::READ_FIX);
|
ut_ad(state > buf_page_t::WRITE_FIX || state < buf_page_t::READ_FIX);
|
||||||
|
static_assert(int{MTR_MEMO_PAGE_S_FIX} == int{RW_S_LATCH}, "");
|
||||||
|
static_assert(int{MTR_MEMO_PAGE_X_FIX} == int{RW_X_LATCH}, "");
|
||||||
|
static_assert(int{MTR_MEMO_PAGE_SX_FIX} == int{RW_SX_LATCH}, "");
|
||||||
|
slot.type= mtr_memo_type_t(rw_latch);
|
||||||
|
|
||||||
switch (rw_latch) {
|
switch (rw_latch) {
|
||||||
default:
|
default:
|
||||||
ut_ad("invalid state" == 0);
|
ut_ad("invalid state" == 0);
|
||||||
break;
|
break;
|
||||||
|
case RW_S_LATCH:
|
||||||
|
block->page.lock.s_lock();
|
||||||
|
break;
|
||||||
case RW_SX_LATCH:
|
case RW_SX_LATCH:
|
||||||
slot.type= MTR_MEMO_PAGE_SX_FIX;
|
|
||||||
block->page.lock.u_lock();
|
block->page.lock.u_lock();
|
||||||
ut_ad(!block->page.is_io_fixed());
|
ut_ad(!block->page.is_io_fixed());
|
||||||
break;
|
break;
|
||||||
case RW_X_LATCH:
|
case RW_X_LATCH:
|
||||||
slot.type= MTR_MEMO_PAGE_X_FIX;
|
|
||||||
block->page.lock.x_lock();
|
block->page.lock.x_lock();
|
||||||
ut_ad(!block->page.is_io_fixed());
|
ut_ad(!block->page.is_io_fixed());
|
||||||
}
|
}
|
||||||
@@ -1463,27 +1428,24 @@ bool mtr_t::memo_contains(const index_lock &lock, mtr_memo_type_t type) const
|
|||||||
ut_ad(type == MTR_MEMO_X_LOCK || type == MTR_MEMO_S_LOCK ||
|
ut_ad(type == MTR_MEMO_X_LOCK || type == MTR_MEMO_S_LOCK ||
|
||||||
type == MTR_MEMO_SX_LOCK);
|
type == MTR_MEMO_SX_LOCK);
|
||||||
|
|
||||||
if (m_memo)
|
for (const mtr_memo_slot_t &slot : m_memo)
|
||||||
{
|
{
|
||||||
for (const mtr_memo_slot_t &slot : *m_memo)
|
if (slot.object == &lock && slot.type == type)
|
||||||
{
|
{
|
||||||
if (slot.object == &lock && slot.type == type)
|
switch (type) {
|
||||||
{
|
case MTR_MEMO_X_LOCK:
|
||||||
switch (type) {
|
ut_ad(lock.have_x());
|
||||||
case MTR_MEMO_X_LOCK:
|
break;
|
||||||
ut_ad(lock.have_x());
|
case MTR_MEMO_SX_LOCK:
|
||||||
break;
|
ut_ad(lock.have_u_or_x());
|
||||||
case MTR_MEMO_SX_LOCK:
|
break;
|
||||||
ut_ad(lock.have_u_or_x());
|
case MTR_MEMO_S_LOCK:
|
||||||
break;
|
ut_ad(lock.have_s());
|
||||||
case MTR_MEMO_S_LOCK:
|
break;
|
||||||
ut_ad(lock.have_s());
|
default:
|
||||||
break;
|
break;
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1511,7 +1473,7 @@ bool mtr_t::memo_contains_flagged(const void *object, ulint flags) const
|
|||||||
MTR_MEMO_MODIFY)) ==
|
MTR_MEMO_MODIFY)) ==
|
||||||
!!(flags & (MTR_MEMO_X_LOCK | MTR_MEMO_SX_LOCK | MTR_MEMO_S_LOCK)));
|
!!(flags & (MTR_MEMO_X_LOCK | MTR_MEMO_SX_LOCK | MTR_MEMO_S_LOCK)));
|
||||||
|
|
||||||
for (const mtr_memo_slot_t &slot : *m_memo)
|
for (const mtr_memo_slot_t &slot : m_memo)
|
||||||
{
|
{
|
||||||
if (object != slot.object)
|
if (object != slot.object)
|
||||||
continue;
|
continue;
|
||||||
@@ -1546,9 +1508,10 @@ buf_block_t* mtr_t::memo_contains_page_flagged(const byte *ptr, ulint flags)
|
|||||||
{
|
{
|
||||||
ptr= page_align(ptr);
|
ptr= page_align(ptr);
|
||||||
|
|
||||||
for (const mtr_memo_slot_t &slot : *m_memo)
|
for (const mtr_memo_slot_t &slot : m_memo)
|
||||||
{
|
{
|
||||||
if (!slot.object || !(flags & slot.type))
|
ut_ad(slot.object);
|
||||||
|
if (!(flags & slot.type))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
buf_page_t *bpage= static_cast<buf_page_t*>(slot.object);
|
buf_page_t *bpage= static_cast<buf_page_t*>(slot.object);
|
||||||
@@ -1569,35 +1532,84 @@ buf_block_t* mtr_t::memo_contains_page_flagged(const byte *ptr, ulint flags)
|
|||||||
|
|
||||||
/** Mark the given latched page as modified.
|
/** Mark the given latched page as modified.
|
||||||
@param block page that will be modified */
|
@param block page that will be modified */
|
||||||
void mtr_t::modify(const buf_block_t &block)
|
void mtr_t::set_modified(const buf_block_t &block)
|
||||||
{
|
{
|
||||||
if (UNIV_UNLIKELY(!m_memo))
|
if (block.page.id().space() >= SRV_TMP_SPACE_ID)
|
||||||
{
|
{
|
||||||
/* This must be PageConverter::update_page() in IMPORT TABLESPACE. */
|
const_cast<buf_block_t&>(block).page.set_temp_modified();
|
||||||
ut_ad(!block.page.in_LRU_list);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
mtr_memo_slot_t *found= nullptr;
|
m_modifications= true;
|
||||||
|
|
||||||
for (mtr_memo_slot_t &slot : *m_memo)
|
if (UNIV_UNLIKELY(m_log_mode == MTR_LOG_NONE))
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (mtr_memo_slot_t &slot : m_memo)
|
||||||
{
|
{
|
||||||
if (slot.object == &block &&
|
if (slot.object == &block &&
|
||||||
slot.type & (MTR_MEMO_PAGE_X_FIX | MTR_MEMO_PAGE_SX_FIX))
|
slot.type & (MTR_MEMO_PAGE_X_FIX | MTR_MEMO_PAGE_SX_FIX))
|
||||||
{
|
{
|
||||||
found= &slot;
|
if (slot.type & MTR_MEMO_MODIFY)
|
||||||
break;
|
ut_ad(m_made_dirty || block.page.oldest_modification() > 1);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
slot.type= static_cast<mtr_memo_type_t>(slot.type | MTR_MEMO_MODIFY);
|
||||||
|
if (!m_made_dirty)
|
||||||
|
m_made_dirty= block.page.oldest_modification() <= 1;
|
||||||
|
}
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (UNIV_UNLIKELY(!found))
|
/* This must be PageConverter::update_page() in IMPORT TABLESPACE. */
|
||||||
|
ut_ad(m_memo.empty());
|
||||||
|
ut_ad(!block.page.in_LRU_list);
|
||||||
|
}
|
||||||
|
|
||||||
|
void mtr_t::init(buf_block_t *b)
|
||||||
|
{
|
||||||
|
const page_id_t id{b->page.id()};
|
||||||
|
ut_ad(is_named_space(id.space()));
|
||||||
|
ut_ad(!m_freed_pages == !m_freed_space);
|
||||||
|
ut_ad(memo_contains_flagged(b, MTR_MEMO_PAGE_X_FIX));
|
||||||
|
|
||||||
|
if (id.space() >= SRV_TMP_SPACE_ID)
|
||||||
|
b->page.set_temp_modified();
|
||||||
|
else
|
||||||
{
|
{
|
||||||
ut_ad("modifying an unlatched page" == 0);
|
for (mtr_memo_slot_t &slot : m_memo)
|
||||||
return;
|
{
|
||||||
|
if (slot.object == b && slot.type & MTR_MEMO_PAGE_X_FIX)
|
||||||
|
{
|
||||||
|
slot.type= MTR_MEMO_PAGE_X_MODIFY;
|
||||||
|
m_modifications= true;
|
||||||
|
if (!m_made_dirty)
|
||||||
|
m_made_dirty= b->page.oldest_modification() <= 1;
|
||||||
|
goto found;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ut_ad("block not X-latched" == 0);
|
||||||
}
|
}
|
||||||
found->type= static_cast<mtr_memo_type_t>(found->type | MTR_MEMO_MODIFY);
|
|
||||||
if (!m_made_dirty)
|
found:
|
||||||
m_made_dirty= is_block_dirtied(block.page);
|
if (UNIV_LIKELY_NULL(m_freed_space) &&
|
||||||
|
m_freed_space->id == id.space() &&
|
||||||
|
m_freed_pages->remove_if_exists(id.page_no()) &&
|
||||||
|
m_freed_pages->empty())
|
||||||
|
{
|
||||||
|
delete m_freed_pages;
|
||||||
|
m_freed_pages= nullptr;
|
||||||
|
m_freed_space= nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
b->page.set_reinit(b->page.state() & buf_page_t::LRU_MASK);
|
||||||
|
|
||||||
|
if (!is_logged())
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_log.close(log_write<INIT_PAGE>(id, &b->page));
|
||||||
|
m_last_offset= FIL_PAGE_TYPE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Free a page.
|
/** Free a page.
|
||||||
@@ -1610,24 +1622,26 @@ void mtr_t::free(const fil_space_t &space, uint32_t offset)
|
|||||||
|
|
||||||
if (is_logged())
|
if (is_logged())
|
||||||
{
|
{
|
||||||
ut_ad(m_memo);
|
|
||||||
buf_block_t *freed= nullptr;
|
buf_block_t *freed= nullptr;
|
||||||
const page_id_t id{space.id, offset};
|
const page_id_t id{space.id, offset};
|
||||||
|
|
||||||
for (auto it= m_memo->rbegin(); it != m_memo->rend(); it++)
|
for (auto it= m_memo.end(); it != m_memo.begin(); )
|
||||||
{
|
{
|
||||||
|
it--;
|
||||||
|
next:
|
||||||
mtr_memo_slot_t &slot= *it;
|
mtr_memo_slot_t &slot= *it;
|
||||||
buf_block_t *block= static_cast<buf_block_t*>(slot.object);
|
buf_block_t *block= static_cast<buf_block_t*>(slot.object);
|
||||||
if (!block);
|
ut_ad(block);
|
||||||
else if (block == freed)
|
if (block == freed)
|
||||||
{
|
{
|
||||||
if (slot.type & (MTR_MEMO_PAGE_SX_FIX | MTR_MEMO_PAGE_X_FIX))
|
if (slot.type & (MTR_MEMO_PAGE_SX_FIX | MTR_MEMO_PAGE_X_FIX))
|
||||||
slot.type= MTR_MEMO_PAGE_X_FIX;
|
slot.type= MTR_MEMO_PAGE_X_FIX;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ut_ad(slot.type == MTR_MEMO_BUF_FIX);
|
ut_ad(slot.type == MTR_MEMO_BUF_FIX);
|
||||||
slot.object= nullptr;
|
|
||||||
block->page.unfix();
|
block->page.unfix();
|
||||||
|
m_memo.erase(it, it + 1);
|
||||||
|
goto next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (slot.type & (MTR_MEMO_PAGE_X_FIX | MTR_MEMO_PAGE_SX_FIX) &&
|
else if (slot.type & (MTR_MEMO_PAGE_X_FIX | MTR_MEMO_PAGE_SX_FIX) &&
|
||||||
@@ -1641,7 +1655,17 @@ void mtr_t::free(const fil_space_t &space, uint32_t offset)
|
|||||||
ut_d(bool upgraded=) block->page.lock.x_lock_upgraded();
|
ut_d(bool upgraded=) block->page.lock.x_lock_upgraded();
|
||||||
ut_ad(upgraded);
|
ut_ad(upgraded);
|
||||||
}
|
}
|
||||||
slot.type= MTR_MEMO_PAGE_X_MODIFY;
|
if (id.space() >= SRV_TMP_SPACE_ID)
|
||||||
|
{
|
||||||
|
block->page.set_temp_modified();
|
||||||
|
slot.type= MTR_MEMO_PAGE_X_FIX;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
slot.type= MTR_MEMO_PAGE_X_MODIFY;
|
||||||
|
if (!m_made_dirty)
|
||||||
|
m_made_dirty= block->page.oldest_modification() <= 1;
|
||||||
|
}
|
||||||
#ifdef BTR_CUR_HASH_ADAPT
|
#ifdef BTR_CUR_HASH_ADAPT
|
||||||
if (block->index)
|
if (block->index)
|
||||||
btr_search_drop_page_hash_index(block, false);
|
btr_search_drop_page_hash_index(block, false);
|
||||||
@@ -1650,8 +1674,22 @@ void mtr_t::free(const fil_space_t &space, uint32_t offset)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (freed && !m_made_dirty)
|
|
||||||
m_made_dirty= is_block_dirtied(freed->page);
|
|
||||||
m_log.close(log_write<FREE_PAGE>(id, nullptr));
|
m_log.close(log_write<FREE_PAGE>(id, nullptr));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void small_vector_base::grow_by_1(void *small, size_t element_size)
|
||||||
|
{
|
||||||
|
const size_t cap= Capacity*= 2, s= cap * element_size;
|
||||||
|
void *new_begin;
|
||||||
|
if (BeginX == small)
|
||||||
|
{
|
||||||
|
new_begin= my_malloc(PSI_NOT_INSTRUMENTED, s, MYF(0));
|
||||||
|
memcpy(new_begin, BeginX, size() * element_size);
|
||||||
|
TRASH_FREE(small, size() * element_size);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
new_begin= my_realloc(PSI_NOT_INSTRUMENTED, BeginX, s, MYF(0));
|
||||||
|
|
||||||
|
BeginX= new_begin;
|
||||||
|
}
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
|
|
||||||
Copyright (c) 2012, 2016, Oracle and/or its affiliates. All Rights Reserved.
|
Copyright (c) 2012, 2016, Oracle and/or its affiliates. All Rights Reserved.
|
||||||
Copyright (c) 2015, 2022, MariaDB Corporation.
|
Copyright (c) 2015, 2023, MariaDB Corporation.
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify it under
|
This program is free software; you can redistribute it and/or modify it under
|
||||||
the terms of the GNU General Public License as published by the Free Software
|
the terms of the GNU General Public License as published by the Free Software
|
||||||
@@ -1617,6 +1617,9 @@ inline dberr_t IndexPurge::purge_pessimistic_delete() noexcept
|
|||||||
dberr_t IndexPurge::purge() noexcept
|
dberr_t IndexPurge::purge() noexcept
|
||||||
{
|
{
|
||||||
btr_pcur_store_position(&m_pcur, &m_mtr);
|
btr_pcur_store_position(&m_pcur, &m_mtr);
|
||||||
|
m_mtr.commit();
|
||||||
|
m_mtr.start();
|
||||||
|
m_mtr.set_log_mode(MTR_LOG_NO_REDO);
|
||||||
dberr_t err= purge_pessimistic_delete();
|
dberr_t err= purge_pessimistic_delete();
|
||||||
|
|
||||||
m_mtr.start();
|
m_mtr.start();
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
|
|
||||||
Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
|
Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
|
||||||
Copyright (c) 2016, 2022, MariaDB Corporation.
|
Copyright (c) 2016, 2023, MariaDB Corporation.
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify it under
|
This program is free software; you can redistribute it and/or modify it under
|
||||||
the terms of the GNU General Public License as published by the Free Software
|
the terms of the GNU General Public License as published by the Free Software
|
||||||
@@ -314,8 +314,10 @@ row_ins_clust_index_entry_by_modify(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (mode != BTR_MODIFY_TREE) {
|
if (mode != BTR_MODIFY_TREE) {
|
||||||
ut_ad((mode & ulint(~BTR_ALREADY_S_LATCHED))
|
ut_ad(mode == BTR_MODIFY_LEAF
|
||||||
== BTR_MODIFY_LEAF);
|
|| mode == BTR_MODIFY_LEAF_ALREADY_LATCHED
|
||||||
|
|| mode == BTR_MODIFY_ROOT_AND_LEAF
|
||||||
|
|| mode == BTR_MODIFY_ROOT_AND_LEAF_ALREADY_LATCHED);
|
||||||
|
|
||||||
/* Try optimistic updating of the record, keeping changes
|
/* Try optimistic updating of the record, keeping changes
|
||||||
within the page */
|
within the page */
|
||||||
@@ -1621,8 +1623,7 @@ row_ins_check_foreign_constraint(
|
|||||||
|
|
||||||
dtuple_set_n_fields_cmp(entry, foreign->n_fields);
|
dtuple_set_n_fields_cmp(entry, foreign->n_fields);
|
||||||
pcur.btr_cur.page_cur.index = check_index;
|
pcur.btr_cur.page_cur.index = check_index;
|
||||||
err = btr_pcur_open(entry, PAGE_CUR_GE, BTR_SEARCH_LEAF, &pcur, 0,
|
err = btr_pcur_open(entry, PAGE_CUR_GE, BTR_SEARCH_LEAF, &pcur, &mtr);
|
||||||
&mtr);
|
|
||||||
if (UNIV_UNLIKELY(err != DB_SUCCESS)) {
|
if (UNIV_UNLIKELY(err != DB_SUCCESS)) {
|
||||||
goto end_scan;
|
goto end_scan;
|
||||||
}
|
}
|
||||||
@@ -2119,7 +2120,7 @@ row_ins_scan_sec_index_for_duplicate(
|
|||||||
pcur.btr_cur.page_cur.index = index;
|
pcur.btr_cur.page_cur.index = index;
|
||||||
trx_t* const trx = thr_get_trx(thr);
|
trx_t* const trx = thr_get_trx(thr);
|
||||||
dberr_t err = btr_pcur_open(entry, PAGE_CUR_GE, BTR_SEARCH_LEAF,
|
dberr_t err = btr_pcur_open(entry, PAGE_CUR_GE, BTR_SEARCH_LEAF,
|
||||||
&pcur, 0, mtr);
|
&pcur, mtr);
|
||||||
if (err != DB_SUCCESS) {
|
if (err != DB_SUCCESS) {
|
||||||
goto end_scan;
|
goto end_scan;
|
||||||
}
|
}
|
||||||
@@ -2546,8 +2547,8 @@ row_ins_index_entry_big_rec(
|
|||||||
index->set_modified(mtr);
|
index->set_modified(mtr);
|
||||||
}
|
}
|
||||||
|
|
||||||
dberr_t error = btr_pcur_open(entry, PAGE_CUR_LE,
|
dberr_t error = btr_pcur_open(entry, PAGE_CUR_LE, BTR_MODIFY_TREE,
|
||||||
BTR_MODIFY_TREE, &pcur, 0, &mtr);
|
&pcur, &mtr);
|
||||||
if (error != DB_SUCCESS) {
|
if (error != DB_SUCCESS) {
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
@@ -2580,6 +2581,42 @@ but GCC 4.8.5 does not support pop_options. */
|
|||||||
# pragma GCC optimize ("O0")
|
# pragma GCC optimize ("O0")
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef WITH_WSREP
|
||||||
|
/** Start bulk insert operation for Galera by appending
|
||||||
|
table-level exclusive key for bulk insert.
|
||||||
|
@param trx transaction
|
||||||
|
@param index index
|
||||||
|
@retval false on success
|
||||||
|
@retval true on failure */
|
||||||
|
ATTRIBUTE_COLD static bool row_ins_wsrep_start_bulk(trx_t *trx, const dict_index_t &index)
|
||||||
|
{
|
||||||
|
char db_buf[NAME_LEN + 1];
|
||||||
|
char tbl_buf[NAME_LEN + 1];
|
||||||
|
ulint db_buf_len, tbl_buf_len;
|
||||||
|
|
||||||
|
if (!index.table->parse_name(db_buf, tbl_buf, &db_buf_len, &tbl_buf_len))
|
||||||
|
{
|
||||||
|
WSREP_ERROR("Parse_name for bulk insert failed: %s",
|
||||||
|
wsrep_thd_query(trx->mysql_thd));
|
||||||
|
trx->error_state = DB_ROLLBACK;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Append table-level exclusive key for bulk insert. */
|
||||||
|
const int rcode = wsrep_thd_append_table_key(trx->mysql_thd, db_buf,
|
||||||
|
tbl_buf, WSREP_SERVICE_KEY_EXCLUSIVE);
|
||||||
|
if (rcode)
|
||||||
|
{
|
||||||
|
WSREP_ERROR("Appending table key for bulk insert failed: %s, %d",
|
||||||
|
wsrep_thd_query(trx->mysql_thd), rcode);
|
||||||
|
trx->error_state = DB_ROLLBACK;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/***************************************************************//**
|
/***************************************************************//**
|
||||||
Tries to insert an entry into a clustered index, ignoring foreign key
|
Tries to insert an entry into a clustered index, ignoring foreign key
|
||||||
constraints. If a record with the same unique key is found, the other
|
constraints. If a record with the same unique key is found, the other
|
||||||
@@ -2605,11 +2642,10 @@ row_ins_clust_index_entry_low(
|
|||||||
que_thr_t* thr) /*!< in: query thread */
|
que_thr_t* thr) /*!< in: query thread */
|
||||||
{
|
{
|
||||||
btr_pcur_t pcur;
|
btr_pcur_t pcur;
|
||||||
btr_cur_t* cursor;
|
|
||||||
dberr_t err = DB_SUCCESS;
|
dberr_t err = DB_SUCCESS;
|
||||||
big_rec_t* big_rec = NULL;
|
big_rec_t* big_rec = NULL;
|
||||||
mtr_t mtr;
|
mtr_t mtr;
|
||||||
ib_uint64_t auto_inc = 0;
|
uint64_t auto_inc = 0;
|
||||||
mem_heap_t* offsets_heap = NULL;
|
mem_heap_t* offsets_heap = NULL;
|
||||||
rec_offs offsets_[REC_OFFS_NORMAL_SIZE];
|
rec_offs offsets_[REC_OFFS_NORMAL_SIZE];
|
||||||
rec_offs* offsets = offsets_;
|
rec_offs* offsets = offsets_;
|
||||||
@@ -2625,7 +2661,7 @@ row_ins_clust_index_entry_low(
|
|||||||
ut_ad(!n_uniq || n_uniq == dict_index_get_n_unique(index));
|
ut_ad(!n_uniq || n_uniq == dict_index_get_n_unique(index));
|
||||||
ut_ad(!trx->in_rollback);
|
ut_ad(!trx->in_rollback);
|
||||||
|
|
||||||
mtr_start(&mtr);
|
mtr.start();
|
||||||
|
|
||||||
if (index->table->is_temporary()) {
|
if (index->table->is_temporary()) {
|
||||||
/* Disable REDO logging as the lifetime of temp-tables is
|
/* Disable REDO logging as the lifetime of temp-tables is
|
||||||
@@ -2665,6 +2701,13 @@ row_ins_clust_index_entry_low(
|
|||||||
dfield->type.mtype,
|
dfield->type.mtype,
|
||||||
dfield->type.prtype
|
dfield->type.prtype
|
||||||
& DATA_UNSIGNED);
|
& DATA_UNSIGNED);
|
||||||
|
if (auto_inc
|
||||||
|
&& mode != BTR_MODIFY_TREE) {
|
||||||
|
mode = btr_latch_mode(
|
||||||
|
BTR_MODIFY_ROOT_AND_LEAF
|
||||||
|
^ BTR_MODIFY_LEAF
|
||||||
|
^ mode);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2674,20 +2717,26 @@ row_ins_clust_index_entry_low(
|
|||||||
the function will return in both low_match and up_match of the
|
the function will return in both low_match and up_match of the
|
||||||
cursor sensible values */
|
cursor sensible values */
|
||||||
pcur.btr_cur.page_cur.index = index;
|
pcur.btr_cur.page_cur.index = index;
|
||||||
err = btr_pcur_open(entry, PAGE_CUR_LE, mode, &pcur, auto_inc, &mtr);
|
err = btr_pcur_open(entry, PAGE_CUR_LE, mode, &pcur, &mtr);
|
||||||
if (err != DB_SUCCESS) {
|
if (err != DB_SUCCESS) {
|
||||||
index->table->file_unreadable = true;
|
index->table->file_unreadable = true;
|
||||||
commit_exit:
|
err_exit:
|
||||||
mtr.commit();
|
mtr.commit();
|
||||||
goto func_exit;
|
goto func_exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
cursor = btr_pcur_get_btr_cur(&pcur);
|
if (auto_inc) {
|
||||||
cursor->thr = thr;
|
buf_block_t* root
|
||||||
|
= mtr.at_savepoint(mode != BTR_MODIFY_ROOT_AND_LEAF);
|
||||||
|
ut_ad(index->page == root->page.id().page_no());
|
||||||
|
page_set_autoinc(root, auto_inc, &mtr, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
btr_pcur_get_btr_cur(&pcur)->thr = thr;
|
||||||
|
|
||||||
#ifdef UNIV_DEBUG
|
#ifdef UNIV_DEBUG
|
||||||
{
|
{
|
||||||
page_t* page = btr_cur_get_page(cursor);
|
page_t* page = btr_pcur_get_page(&pcur);
|
||||||
rec_t* first_rec = page_rec_get_next(
|
rec_t* first_rec = page_rec_get_next(
|
||||||
page_get_infimum_rec(page));
|
page_get_infimum_rec(page));
|
||||||
|
|
||||||
@@ -2696,7 +2745,7 @@ commit_exit:
|
|||||||
}
|
}
|
||||||
#endif /* UNIV_DEBUG */
|
#endif /* UNIV_DEBUG */
|
||||||
|
|
||||||
block = btr_cur_get_block(cursor);
|
block = btr_pcur_get_block(&pcur);
|
||||||
|
|
||||||
DBUG_EXECUTE_IF("row_ins_row_level", goto skip_bulk_insert;);
|
DBUG_EXECUTE_IF("row_ins_row_level", goto skip_bulk_insert;);
|
||||||
|
|
||||||
@@ -2710,7 +2759,7 @@ commit_exit:
|
|||||||
&& !index->table->n_rec_locks
|
&& !index->table->n_rec_locks
|
||||||
&& !index->table->is_active_ddl()
|
&& !index->table->is_active_ddl()
|
||||||
&& !index->table->has_spatial_index()
|
&& !index->table->has_spatial_index()
|
||||||
&& !trx->is_wsrep() /* FIXME: MDEV-24623 */
|
&& !index->table->versioned()
|
||||||
&& !thd_is_slave(trx->mysql_thd) /* FIXME: MDEV-24622 */) {
|
&& !thd_is_slave(trx->mysql_thd) /* FIXME: MDEV-24622 */) {
|
||||||
DEBUG_SYNC_C("empty_root_page_insert");
|
DEBUG_SYNC_C("empty_root_page_insert");
|
||||||
|
|
||||||
@@ -2722,7 +2771,7 @@ commit_exit:
|
|||||||
if (err != DB_SUCCESS) {
|
if (err != DB_SUCCESS) {
|
||||||
trx->error_state = err;
|
trx->error_state = err;
|
||||||
trx->bulk_insert = false;
|
trx->bulk_insert = false;
|
||||||
goto commit_exit;
|
goto err_exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (index->table->n_rec_locks) {
|
if (index->table->n_rec_locks) {
|
||||||
@@ -2731,6 +2780,16 @@ avoid_bulk:
|
|||||||
goto skip_bulk_insert;
|
goto skip_bulk_insert;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef WITH_WSREP
|
||||||
|
if (trx->is_wsrep())
|
||||||
|
{
|
||||||
|
if (!wsrep_thd_is_local_transaction(trx->mysql_thd))
|
||||||
|
goto skip_bulk_insert;
|
||||||
|
if (row_ins_wsrep_start_bulk(trx, *index))
|
||||||
|
goto err_exit;
|
||||||
|
}
|
||||||
|
#endif /* WITH_WSREP */
|
||||||
|
|
||||||
#ifdef BTR_CUR_HASH_ADAPT
|
#ifdef BTR_CUR_HASH_ADAPT
|
||||||
if (btr_search_enabled) {
|
if (btr_search_enabled) {
|
||||||
btr_search_x_lock_all();
|
btr_search_x_lock_all();
|
||||||
@@ -2754,7 +2813,7 @@ avoid_bulk:
|
|||||||
goto avoid_bulk;
|
goto avoid_bulk;
|
||||||
}
|
}
|
||||||
|
|
||||||
goto commit_exit;
|
goto err_exit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2765,7 +2824,7 @@ skip_bulk_insert:
|
|||||||
ut_ad(index->is_instant());
|
ut_ad(index->is_instant());
|
||||||
ut_ad(!dict_index_is_online_ddl(index));
|
ut_ad(!dict_index_is_online_ddl(index));
|
||||||
|
|
||||||
const rec_t* rec = btr_cur_get_rec(cursor);
|
const rec_t* rec = btr_pcur_get_rec(&pcur);
|
||||||
|
|
||||||
if (rec_get_info_bits(rec, page_rec_is_comp(rec))
|
if (rec_get_info_bits(rec, page_rec_is_comp(rec))
|
||||||
& REC_INFO_MIN_REC_FLAG) {
|
& REC_INFO_MIN_REC_FLAG) {
|
||||||
@@ -2774,16 +2833,17 @@ skip_bulk_insert:
|
|||||||
goto err_exit;
|
goto err_exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
ut_ad(!row_ins_must_modify_rec(cursor));
|
ut_ad(!row_ins_must_modify_rec(&pcur.btr_cur));
|
||||||
goto do_insert;
|
goto do_insert;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rec_is_metadata(btr_cur_get_rec(cursor), *index)) {
|
if (rec_is_metadata(btr_pcur_get_rec(&pcur), *index)) {
|
||||||
goto do_insert;
|
goto do_insert;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (n_uniq
|
if (n_uniq
|
||||||
&& (cursor->up_match >= n_uniq || cursor->low_match >= n_uniq)) {
|
&& (pcur.btr_cur.up_match >= n_uniq
|
||||||
|
|| pcur.btr_cur.low_match >= n_uniq)) {
|
||||||
|
|
||||||
if (flags
|
if (flags
|
||||||
== (BTR_CREATE_FLAG | BTR_NO_LOCKING_FLAG
|
== (BTR_CREATE_FLAG | BTR_NO_LOCKING_FLAG
|
||||||
@@ -2791,7 +2851,7 @@ skip_bulk_insert:
|
|||||||
/* Set no locks when applying log
|
/* Set no locks when applying log
|
||||||
in online table rebuild. Only check for duplicates. */
|
in online table rebuild. Only check for duplicates. */
|
||||||
err = row_ins_duplicate_error_in_clust_online(
|
err = row_ins_duplicate_error_in_clust_online(
|
||||||
n_uniq, entry, cursor,
|
n_uniq, entry, &pcur.btr_cur,
|
||||||
&offsets, &offsets_heap);
|
&offsets, &offsets_heap);
|
||||||
|
|
||||||
switch (err) {
|
switch (err) {
|
||||||
@@ -2802,26 +2862,24 @@ skip_bulk_insert:
|
|||||||
/* fall through */
|
/* fall through */
|
||||||
case DB_SUCCESS_LOCKED_REC:
|
case DB_SUCCESS_LOCKED_REC:
|
||||||
case DB_DUPLICATE_KEY:
|
case DB_DUPLICATE_KEY:
|
||||||
trx->error_info = cursor->index();
|
trx->error_info = index;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* Note that the following may return also
|
/* Note that the following may return also
|
||||||
DB_LOCK_WAIT */
|
DB_LOCK_WAIT */
|
||||||
|
|
||||||
err = row_ins_duplicate_error_in_clust(
|
err = row_ins_duplicate_error_in_clust(
|
||||||
flags, cursor, entry, thr);
|
flags, &pcur.btr_cur, entry, thr);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (err != DB_SUCCESS) {
|
if (err != DB_SUCCESS) {
|
||||||
err_exit:
|
goto err_exit;
|
||||||
mtr_commit(&mtr);
|
|
||||||
goto func_exit;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Note: Allowing duplicates would qualify for modification of
|
/* Note: Allowing duplicates would qualify for modification of
|
||||||
an existing record as the new entry is exactly same as old entry. */
|
an existing record as the new entry is exactly same as old entry. */
|
||||||
if (row_ins_must_modify_rec(cursor)) {
|
if (row_ins_must_modify_rec(&pcur.btr_cur)) {
|
||||||
/* There is already an index entry with a long enough common
|
/* There is already an index entry with a long enough common
|
||||||
prefix, we must convert the insert into a modify of an
|
prefix, we must convert the insert into a modify of an
|
||||||
existing record */
|
existing record */
|
||||||
@@ -2839,10 +2897,13 @@ do_insert:
|
|||||||
rec_t* insert_rec;
|
rec_t* insert_rec;
|
||||||
|
|
||||||
if (mode != BTR_MODIFY_TREE) {
|
if (mode != BTR_MODIFY_TREE) {
|
||||||
ut_ad(mode == BTR_MODIFY_LEAF ||
|
ut_ad(mode == BTR_MODIFY_LEAF
|
||||||
mode == BTR_MODIFY_LEAF_ALREADY_LATCHED);
|
|| mode == BTR_MODIFY_LEAF_ALREADY_LATCHED
|
||||||
|
|| mode == BTR_MODIFY_ROOT_AND_LEAF
|
||||||
|
|| mode
|
||||||
|
== BTR_MODIFY_ROOT_AND_LEAF_ALREADY_LATCHED);
|
||||||
err = btr_cur_optimistic_insert(
|
err = btr_cur_optimistic_insert(
|
||||||
flags, cursor, &offsets, &offsets_heap,
|
flags, &pcur.btr_cur, &offsets, &offsets_heap,
|
||||||
entry, &insert_rec, &big_rec,
|
entry, &insert_rec, &big_rec,
|
||||||
n_ext, thr, &mtr);
|
n_ext, thr, &mtr);
|
||||||
} else {
|
} else {
|
||||||
@@ -2851,17 +2912,15 @@ do_insert:
|
|||||||
goto err_exit;
|
goto err_exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
DEBUG_SYNC_C("before_insert_pessimitic_row_ins_clust");
|
|
||||||
|
|
||||||
err = btr_cur_optimistic_insert(
|
err = btr_cur_optimistic_insert(
|
||||||
flags, cursor,
|
flags, &pcur.btr_cur,
|
||||||
&offsets, &offsets_heap,
|
&offsets, &offsets_heap,
|
||||||
entry, &insert_rec, &big_rec,
|
entry, &insert_rec, &big_rec,
|
||||||
n_ext, thr, &mtr);
|
n_ext, thr, &mtr);
|
||||||
|
|
||||||
if (err == DB_FAIL) {
|
if (err == DB_FAIL) {
|
||||||
err = btr_cur_pessimistic_insert(
|
err = btr_cur_pessimistic_insert(
|
||||||
flags, cursor,
|
flags, &pcur.btr_cur,
|
||||||
&offsets, &offsets_heap,
|
&offsets, &offsets_heap,
|
||||||
entry, &insert_rec, &big_rec,
|
entry, &insert_rec, &big_rec,
|
||||||
n_ext, thr, &mtr);
|
n_ext, thr, &mtr);
|
||||||
@@ -2973,9 +3032,7 @@ row_ins_sec_index_entry_low(
|
|||||||
rtr_init_rtr_info(&rtr_info, false, &cursor, index, false);
|
rtr_init_rtr_info(&rtr_info, false, &cursor, index, false);
|
||||||
rtr_info_update_btr(&cursor, &rtr_info);
|
rtr_info_update_btr(&cursor, &rtr_info);
|
||||||
|
|
||||||
err = btr_cur_search_to_nth_level(0, entry,
|
err = rtr_insert_leaf(&cursor, entry, search_mode, &mtr);
|
||||||
PAGE_CUR_RTREE_INSERT,
|
|
||||||
search_mode, &cursor, &mtr);
|
|
||||||
|
|
||||||
if (err == DB_SUCCESS && search_mode == BTR_MODIFY_LEAF
|
if (err == DB_SUCCESS && search_mode == BTR_MODIFY_LEAF
|
||||||
&& rtr_info.mbr_adj) {
|
&& rtr_info.mbr_adj) {
|
||||||
@@ -2991,9 +3048,8 @@ row_ins_sec_index_entry_low(
|
|||||||
} else {
|
} else {
|
||||||
index->set_modified(mtr);
|
index->set_modified(mtr);
|
||||||
}
|
}
|
||||||
err = btr_cur_search_to_nth_level(
|
err = rtr_insert_leaf(&cursor, entry,
|
||||||
0, entry, PAGE_CUR_RTREE_INSERT,
|
search_mode, &mtr);
|
||||||
search_mode, &cursor, &mtr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DBUG_EXECUTE_IF(
|
DBUG_EXECUTE_IF(
|
||||||
@@ -3009,8 +3065,8 @@ row_ins_sec_index_entry_low(
|
|||||||
: BTR_INSERT));
|
: BTR_INSERT));
|
||||||
}
|
}
|
||||||
|
|
||||||
err = btr_cur_search_to_nth_level(0, entry, PAGE_CUR_LE,
|
err = cursor.search_leaf(entry, PAGE_CUR_LE, search_mode,
|
||||||
search_mode, &cursor, &mtr);
|
&mtr);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (err != DB_SUCCESS) {
|
if (err != DB_SUCCESS) {
|
||||||
@@ -3086,12 +3142,12 @@ row_ins_sec_index_entry_low(
|
|||||||
prevent any insertion of a duplicate by another
|
prevent any insertion of a duplicate by another
|
||||||
transaction. Let us now reposition the cursor and
|
transaction. Let us now reposition the cursor and
|
||||||
continue the insertion (bypassing the change buffer). */
|
continue the insertion (bypassing the change buffer). */
|
||||||
err = btr_cur_search_to_nth_level(
|
err = cursor.search_leaf(
|
||||||
0, entry, PAGE_CUR_LE,
|
entry, PAGE_CUR_LE,
|
||||||
btr_latch_mode(search_mode
|
btr_latch_mode(search_mode
|
||||||
& ~(BTR_INSERT
|
& ~(BTR_INSERT
|
||||||
| BTR_IGNORE_SEC_UNIQUE)),
|
| BTR_IGNORE_SEC_UNIQUE)),
|
||||||
&cursor, &mtr);
|
&mtr);
|
||||||
if (err != DB_SUCCESS) {
|
if (err != DB_SUCCESS) {
|
||||||
goto func_exit;
|
goto func_exit;
|
||||||
}
|
}
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
|
|
||||||
Copyright (c) 2011, 2018, Oracle and/or its affiliates. All Rights Reserved.
|
Copyright (c) 2011, 2018, Oracle and/or its affiliates. All Rights Reserved.
|
||||||
Copyright (c) 2017, 2022, MariaDB Corporation.
|
Copyright (c) 2017, 2023, MariaDB Corporation.
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify it under
|
This program is free software; you can redistribute it and/or modify it under
|
||||||
the terms of the GNU General Public License as published by the Free Software
|
the terms of the GNU General Public License as published by the Free Software
|
||||||
@@ -1696,8 +1696,8 @@ err_exit:
|
|||||||
mtr->start();
|
mtr->start();
|
||||||
index->set_modified(*mtr);
|
index->set_modified(*mtr);
|
||||||
pcur->btr_cur.page_cur.index = index;
|
pcur->btr_cur.page_cur.index = index;
|
||||||
error = btr_pcur_open(entry, PAGE_CUR_LE,
|
error = btr_pcur_open(entry, PAGE_CUR_LE, BTR_PURGE_TREE, pcur,
|
||||||
BTR_PURGE_TREE, pcur, 0, mtr);
|
mtr);
|
||||||
if (error) {
|
if (error) {
|
||||||
goto err_exit;
|
goto err_exit;
|
||||||
}
|
}
|
||||||
@@ -1780,8 +1780,8 @@ row_log_table_apply_delete(
|
|||||||
|
|
||||||
mtr_start(&mtr);
|
mtr_start(&mtr);
|
||||||
index->set_modified(mtr);
|
index->set_modified(mtr);
|
||||||
dberr_t err = btr_pcur_open(old_pk, PAGE_CUR_LE,
|
dberr_t err = btr_pcur_open(old_pk, PAGE_CUR_LE, BTR_PURGE_TREE, &pcur,
|
||||||
BTR_PURGE_TREE, &pcur, 0, &mtr);
|
&mtr);
|
||||||
if (err != DB_SUCCESS) {
|
if (err != DB_SUCCESS) {
|
||||||
goto all_done;
|
goto all_done;
|
||||||
}
|
}
|
||||||
@@ -1917,8 +1917,8 @@ row_log_table_apply_update(
|
|||||||
|
|
||||||
mtr.start();
|
mtr.start();
|
||||||
index->set_modified(mtr);
|
index->set_modified(mtr);
|
||||||
error = btr_pcur_open(old_pk, PAGE_CUR_LE,
|
error = btr_pcur_open(old_pk, PAGE_CUR_LE, BTR_MODIFY_TREE, &pcur,
|
||||||
BTR_MODIFY_TREE, &pcur, 0, &mtr);
|
&mtr);
|
||||||
if (error != DB_SUCCESS) {
|
if (error != DB_SUCCESS) {
|
||||||
func_exit:
|
func_exit:
|
||||||
mtr.commit();
|
mtr.commit();
|
||||||
@@ -3084,11 +3084,8 @@ row_log_apply_op_low(
|
|||||||
record. The operation may already have been performed,
|
record. The operation may already have been performed,
|
||||||
depending on when the row in the clustered index was
|
depending on when the row in the clustered index was
|
||||||
scanned. */
|
scanned. */
|
||||||
*error = btr_cur_search_to_nth_level(0, entry, PAGE_CUR_LE,
|
*error = cursor.search_leaf(entry, PAGE_CUR_LE, has_index_lock
|
||||||
has_index_lock
|
? BTR_MODIFY_TREE : BTR_MODIFY_LEAF, &mtr);
|
||||||
? BTR_MODIFY_TREE
|
|
||||||
: BTR_MODIFY_LEAF,
|
|
||||||
&cursor, &mtr);
|
|
||||||
if (UNIV_UNLIKELY(*error != DB_SUCCESS)) {
|
if (UNIV_UNLIKELY(*error != DB_SUCCESS)) {
|
||||||
goto func_exit;
|
goto func_exit;
|
||||||
}
|
}
|
||||||
@@ -3138,9 +3135,9 @@ row_log_apply_op_low(
|
|||||||
mtr_commit(&mtr);
|
mtr_commit(&mtr);
|
||||||
mtr_start(&mtr);
|
mtr_start(&mtr);
|
||||||
index->set_modified(mtr);
|
index->set_modified(mtr);
|
||||||
*error = btr_cur_search_to_nth_level(
|
*error = cursor.search_leaf(entry, PAGE_CUR_LE,
|
||||||
0, entry, PAGE_CUR_LE,
|
BTR_MODIFY_TREE,
|
||||||
BTR_MODIFY_TREE, &cursor, &mtr);
|
&mtr);
|
||||||
if (UNIV_UNLIKELY(*error != DB_SUCCESS)) {
|
if (UNIV_UNLIKELY(*error != DB_SUCCESS)) {
|
||||||
goto func_exit;
|
goto func_exit;
|
||||||
}
|
}
|
||||||
@@ -3242,9 +3239,9 @@ insert_the_rec:
|
|||||||
mtr_commit(&mtr);
|
mtr_commit(&mtr);
|
||||||
mtr_start(&mtr);
|
mtr_start(&mtr);
|
||||||
index->set_modified(mtr);
|
index->set_modified(mtr);
|
||||||
*error = btr_cur_search_to_nth_level(
|
*error = cursor.search_leaf(entry, PAGE_CUR_LE,
|
||||||
0, entry, PAGE_CUR_LE,
|
BTR_MODIFY_TREE,
|
||||||
BTR_MODIFY_TREE, &cursor, &mtr);
|
&mtr);
|
||||||
if (*error != DB_SUCCESS) {
|
if (*error != DB_SUCCESS) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@@ -150,9 +150,8 @@ public:
|
|||||||
false);
|
false);
|
||||||
rtr_info_update_btr(&ins_cur, &rtr_info);
|
rtr_info_update_btr(&ins_cur, &rtr_info);
|
||||||
|
|
||||||
error = btr_cur_search_to_nth_level(
|
error = rtr_insert_leaf(&ins_cur, dtuple,
|
||||||
0, dtuple, PAGE_CUR_RTREE_INSERT,
|
BTR_MODIFY_LEAF, &mtr);
|
||||||
BTR_MODIFY_LEAF, &ins_cur, &mtr);
|
|
||||||
|
|
||||||
/* It need to update MBR in parent entry,
|
/* It need to update MBR in parent entry,
|
||||||
so change search mode to BTR_MODIFY_TREE */
|
so change search mode to BTR_MODIFY_TREE */
|
||||||
@@ -164,10 +163,8 @@ public:
|
|||||||
rtr_info_update_btr(&ins_cur, &rtr_info);
|
rtr_info_update_btr(&ins_cur, &rtr_info);
|
||||||
mtr.start();
|
mtr.start();
|
||||||
index->set_modified(mtr);
|
index->set_modified(mtr);
|
||||||
error = btr_cur_search_to_nth_level(
|
error = rtr_insert_leaf(&ins_cur, dtuple,
|
||||||
0, dtuple,
|
BTR_MODIFY_TREE, &mtr);
|
||||||
PAGE_CUR_RTREE_INSERT,
|
|
||||||
BTR_MODIFY_TREE, &ins_cur, &mtr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (error == DB_SUCCESS) {
|
if (error == DB_SUCCESS) {
|
||||||
@@ -189,11 +186,8 @@ public:
|
|||||||
&ins_cur, index, false);
|
&ins_cur, index, false);
|
||||||
|
|
||||||
rtr_info_update_btr(&ins_cur, &rtr_info);
|
rtr_info_update_btr(&ins_cur, &rtr_info);
|
||||||
error = btr_cur_search_to_nth_level(
|
error = rtr_insert_leaf(&ins_cur, dtuple,
|
||||||
0, dtuple,
|
BTR_MODIFY_TREE, &mtr);
|
||||||
PAGE_CUR_RTREE_INSERT,
|
|
||||||
BTR_MODIFY_TREE,
|
|
||||||
&ins_cur, &mtr);
|
|
||||||
|
|
||||||
if (error == DB_SUCCESS) {
|
if (error == DB_SUCCESS) {
|
||||||
error = btr_cur_pessimistic_insert(
|
error = btr_cur_pessimistic_insert(
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
|
|
||||||
Copyright (c) 1997, 2017, Oracle and/or its affiliates. All Rights Reserved.
|
Copyright (c) 1997, 2017, Oracle and/or its affiliates. All Rights Reserved.
|
||||||
Copyright (c) 2017, 2022, MariaDB Corporation.
|
Copyright (c) 2017, 2023, MariaDB Corporation.
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify it under
|
This program is free software; you can redistribute it and/or modify it under
|
||||||
the terms of the GNU General Public License as published by the Free Software
|
the terms of the GNU General Public License as published by the Free Software
|
||||||
@@ -104,7 +104,7 @@ bool
|
|||||||
row_purge_remove_clust_if_poss_low(
|
row_purge_remove_clust_if_poss_low(
|
||||||
/*===============================*/
|
/*===============================*/
|
||||||
purge_node_t* node, /*!< in/out: row purge node */
|
purge_node_t* node, /*!< in/out: row purge node */
|
||||||
btr_latch_mode mode) /*!< in: BTR_MODIFY_LEAF or BTR_MODIFY_TREE */
|
btr_latch_mode mode) /*!< in: BTR_MODIFY_LEAF or BTR_PURGE_TREE */
|
||||||
{
|
{
|
||||||
dict_index_t* index = dict_table_get_first_index(node->table);
|
dict_index_t* index = dict_table_get_first_index(node->table);
|
||||||
table_id_t table_id = 0;
|
table_id_t table_id = 0;
|
||||||
@@ -342,17 +342,20 @@ row_purge_remove_sec_if_poss_tree(
|
|||||||
ibool success = TRUE;
|
ibool success = TRUE;
|
||||||
dberr_t err;
|
dberr_t err;
|
||||||
mtr_t mtr;
|
mtr_t mtr;
|
||||||
enum row_search_result search_result;
|
|
||||||
|
|
||||||
log_free_check();
|
log_free_check();
|
||||||
mtr.start();
|
mtr.start();
|
||||||
index->set_modified(mtr);
|
index->set_modified(mtr);
|
||||||
pcur.btr_cur.page_cur.index = index;
|
pcur.btr_cur.page_cur.index = index;
|
||||||
|
|
||||||
search_result = row_search_index_entry(entry, BTR_PURGE_TREE,
|
if (index->is_spatial()) {
|
||||||
&pcur, &mtr);
|
if (!rtr_search(entry, BTR_PURGE_TREE, &pcur, &mtr)) {
|
||||||
|
goto found;
|
||||||
|
}
|
||||||
|
goto func_exit;
|
||||||
|
}
|
||||||
|
|
||||||
switch (search_result) {
|
switch (row_search_index_entry(entry, BTR_PURGE_TREE, &pcur, &mtr)) {
|
||||||
case ROW_NOT_FOUND:
|
case ROW_NOT_FOUND:
|
||||||
/* Not found. This is a legitimate condition. In a
|
/* Not found. This is a legitimate condition. In a
|
||||||
rollback, InnoDB will remove secondary recs that would
|
rollback, InnoDB will remove secondary recs that would
|
||||||
@@ -381,6 +384,7 @@ row_purge_remove_sec_if_poss_tree(
|
|||||||
which cannot be purged yet, requires its existence. If some requires,
|
which cannot be purged yet, requires its existence. If some requires,
|
||||||
we should do nothing. */
|
we should do nothing. */
|
||||||
|
|
||||||
|
found:
|
||||||
if (row_purge_poss_sec(node, index, entry, &pcur, &mtr, true)) {
|
if (row_purge_poss_sec(node, index, entry, &pcur, &mtr, true)) {
|
||||||
|
|
||||||
/* Remove the index record, which should have been
|
/* Remove the index record, which should have been
|
||||||
@@ -439,8 +443,6 @@ row_purge_remove_sec_if_poss_leaf(
|
|||||||
{
|
{
|
||||||
mtr_t mtr;
|
mtr_t mtr;
|
||||||
btr_pcur_t pcur;
|
btr_pcur_t pcur;
|
||||||
enum btr_latch_mode mode;
|
|
||||||
enum row_search_result search_result;
|
|
||||||
bool success = true;
|
bool success = true;
|
||||||
|
|
||||||
log_free_check();
|
log_free_check();
|
||||||
@@ -449,31 +451,27 @@ row_purge_remove_sec_if_poss_leaf(
|
|||||||
mtr.start();
|
mtr.start();
|
||||||
index->set_modified(mtr);
|
index->set_modified(mtr);
|
||||||
|
|
||||||
/* Change buffering is disabled for spatial index and
|
|
||||||
virtual index. */
|
|
||||||
mode = (index->type & (DICT_SPATIAL | DICT_VIRTUAL))
|
|
||||||
? BTR_MODIFY_LEAF : BTR_PURGE_LEAF;
|
|
||||||
pcur.btr_cur.page_cur.index = index;
|
pcur.btr_cur.page_cur.index = index;
|
||||||
|
|
||||||
/* Set the purge node for the call to row_purge_poss_sec(). */
|
/* Set the purge node for the call to row_purge_poss_sec(). */
|
||||||
pcur.btr_cur.purge_node = node;
|
pcur.btr_cur.purge_node = node;
|
||||||
if (index->is_spatial()) {
|
if (index->is_spatial()) {
|
||||||
pcur.btr_cur.thr = NULL;
|
pcur.btr_cur.thr = NULL;
|
||||||
index->lock.u_lock(SRW_LOCK_CALL);
|
if (!rtr_search(entry, BTR_MODIFY_LEAF, &pcur, &mtr)) {
|
||||||
search_result = row_search_index_entry(
|
goto found;
|
||||||
entry, mode, &pcur, &mtr);
|
}
|
||||||
index->lock.u_unlock();
|
goto func_exit;
|
||||||
} else {
|
|
||||||
/* Set the query thread, so that ibuf_insert_low() will be
|
|
||||||
able to invoke thd_get_trx(). */
|
|
||||||
pcur.btr_cur.thr = static_cast<que_thr_t*>(
|
|
||||||
que_node_get_parent(node));
|
|
||||||
search_result = row_search_index_entry(
|
|
||||||
entry, mode, &pcur, &mtr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (search_result) {
|
/* Set the query thread, so that ibuf_insert_low() will be
|
||||||
|
able to invoke thd_get_trx(). */
|
||||||
|
pcur.btr_cur.thr = static_cast<que_thr_t*>(que_node_get_parent(node));
|
||||||
|
|
||||||
|
switch (row_search_index_entry(entry, index->has_virtual()
|
||||||
|
? BTR_MODIFY_LEAF : BTR_PURGE_LEAF,
|
||||||
|
&pcur, &mtr)) {
|
||||||
case ROW_FOUND:
|
case ROW_FOUND:
|
||||||
|
found:
|
||||||
/* Before attempting to purge a record, check
|
/* Before attempting to purge a record, check
|
||||||
if it is safe to do so. */
|
if it is safe to do so. */
|
||||||
if (row_purge_poss_sec(node, index, entry, &pcur, &mtr, false)) {
|
if (row_purge_poss_sec(node, index, entry, &pcur, &mtr, false)) {
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
|
|
||||||
Copyright (c) 1996, 2018, Oracle and/or its affiliates. All Rights Reserved.
|
Copyright (c) 1996, 2018, Oracle and/or its affiliates. All Rights Reserved.
|
||||||
Copyright (c) 2018, 2022, MariaDB Corporation.
|
Copyright (c) 2018, 2023, MariaDB Corporation.
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify it under
|
This program is free software; you can redistribute it and/or modify it under
|
||||||
the terms of the GNU General Public License as published by the Free Software
|
the terms of the GNU General Public License as published by the Free Software
|
||||||
@@ -1216,7 +1216,7 @@ row_search_on_row_ref(
|
|||||||
& REC_INFO_MIN_REC_FLAG;
|
& REC_INFO_MIN_REC_FLAG;
|
||||||
} else {
|
} else {
|
||||||
ut_a(ref->n_fields == index->n_uniq);
|
ut_a(ref->n_fields == index->n_uniq);
|
||||||
if (btr_pcur_open(ref, PAGE_CUR_LE, mode, pcur, 0, mtr)
|
if (btr_pcur_open(ref, PAGE_CUR_LE, mode, pcur, mtr)
|
||||||
!= DB_SUCCESS) {
|
!= DB_SUCCESS) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -1278,21 +1278,13 @@ row_search_index_entry(
|
|||||||
|
|
||||||
ut_ad(dtuple_check_typed(entry));
|
ut_ad(dtuple_check_typed(entry));
|
||||||
|
|
||||||
if (pcur->index()->is_spatial()) {
|
if (btr_pcur_open(entry, PAGE_CUR_LE, mode, pcur, mtr) != DB_SUCCESS) {
|
||||||
if (rtr_pcur_open(pcur->index(), entry, mode, pcur, mtr)) {
|
return ROW_NOT_FOUND;
|
||||||
return ROW_NOT_FOUND;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (btr_pcur_open(entry, PAGE_CUR_LE, mode, pcur, 0, mtr)
|
|
||||||
!= DB_SUCCESS) {
|
|
||||||
return ROW_NOT_FOUND;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (btr_pcur_get_btr_cur(pcur)->flag) {
|
switch (btr_pcur_get_btr_cur(pcur)->flag) {
|
||||||
case BTR_CUR_DELETE_REF:
|
case BTR_CUR_DELETE_REF:
|
||||||
ut_ad(!(~mode & BTR_DELETE));
|
ut_ad(!(~mode & BTR_DELETE));
|
||||||
ut_ad(!pcur->index()->is_spatial());
|
|
||||||
return(ROW_NOT_DELETED_REF);
|
return(ROW_NOT_DELETED_REF);
|
||||||
|
|
||||||
case BTR_CUR_DEL_MARK_IBUF:
|
case BTR_CUR_DEL_MARK_IBUF:
|
||||||
|
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
Copyright (c) 1997, 2017, Oracle and/or its affiliates. All Rights Reserved.
|
Copyright (c) 1997, 2017, Oracle and/or its affiliates. All Rights Reserved.
|
||||||
Copyright (c) 2008, Google Inc.
|
Copyright (c) 2008, Google Inc.
|
||||||
Copyright (c) 2015, 2022, MariaDB Corporation.
|
Copyright (c) 2015, 2023, MariaDB Corporation.
|
||||||
|
|
||||||
Portions of this file contain modifications contributed and copyrighted by
|
Portions of this file contain modifications contributed and copyrighted by
|
||||||
Google, Inc. Those modifications are gratefully acknowledged and are described
|
Google, Inc. Those modifications are gratefully acknowledged and are described
|
||||||
@@ -4771,7 +4771,7 @@ wait_table_again:
|
|||||||
pcur->btr_cur.thr = thr;
|
pcur->btr_cur.thr = thr;
|
||||||
pcur->old_rec = nullptr;
|
pcur->old_rec = nullptr;
|
||||||
|
|
||||||
if (dict_index_is_spatial(index)) {
|
if (index->is_spatial()) {
|
||||||
if (!prebuilt->rtr_info) {
|
if (!prebuilt->rtr_info) {
|
||||||
prebuilt->rtr_info = rtr_create_rtr_info(
|
prebuilt->rtr_info = rtr_create_rtr_info(
|
||||||
set_also_gap_locks, true,
|
set_also_gap_locks, true,
|
||||||
@@ -4787,10 +4787,13 @@ wait_table_again:
|
|||||||
prebuilt->rtr_info->search_tuple = search_tuple;
|
prebuilt->rtr_info->search_tuple = search_tuple;
|
||||||
prebuilt->rtr_info->search_mode = mode;
|
prebuilt->rtr_info->search_mode = mode;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
err = btr_pcur_open_with_no_init(search_tuple, mode,
|
err = rtr_search_leaf(pcur, search_tuple, mode, &mtr);
|
||||||
BTR_SEARCH_LEAF, pcur, &mtr);
|
} else {
|
||||||
|
err = btr_pcur_open_with_no_init(search_tuple, mode,
|
||||||
|
BTR_SEARCH_LEAF,
|
||||||
|
pcur, &mtr);
|
||||||
|
}
|
||||||
|
|
||||||
if (err != DB_SUCCESS) {
|
if (err != DB_SUCCESS) {
|
||||||
page_corrupted:
|
page_corrupted:
|
||||||
@@ -5767,8 +5770,7 @@ next_rec_after_check:
|
|||||||
|
|
||||||
if (spatial_search) {
|
if (spatial_search) {
|
||||||
/* No need to do store restore for R-tree */
|
/* No need to do store restore for R-tree */
|
||||||
mtr.commit();
|
mtr.rollback_to_savepoint(0);
|
||||||
mtr.start();
|
|
||||||
} else if (mtr_extra_clust_savepoint) {
|
} else if (mtr_extra_clust_savepoint) {
|
||||||
/* We must release any clustered index latches
|
/* We must release any clustered index latches
|
||||||
if we are moving to the next non-clustered
|
if we are moving to the next non-clustered
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
|
|
||||||
Copyright (c) 1997, 2017, Oracle and/or its affiliates. All Rights Reserved.
|
Copyright (c) 1997, 2017, Oracle and/or its affiliates. All Rights Reserved.
|
||||||
Copyright (c) 2017, 2022, MariaDB Corporation.
|
Copyright (c) 2017, 2023, MariaDB Corporation.
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify it under
|
This program is free software; you can redistribute it and/or modify it under
|
||||||
the terms of the GNU General Public License as published by the Free Software
|
the terms of the GNU General Public License as published by the Free Software
|
||||||
@@ -233,7 +233,7 @@ func_exit:
|
|||||||
if (err == DB_SUCCESS && node->rec_type == TRX_UNDO_INSERT_METADATA) {
|
if (err == DB_SUCCESS && node->rec_type == TRX_UNDO_INSERT_METADATA) {
|
||||||
/* When rolling back the very first instant ADD COLUMN
|
/* When rolling back the very first instant ADD COLUMN
|
||||||
operation, reset the root page to the basic state. */
|
operation, reset the root page to the basic state. */
|
||||||
err = btr_reset_instant(*index, true, &mtr);
|
btr_reset_instant(*index, true, &mtr);
|
||||||
}
|
}
|
||||||
|
|
||||||
btr_pcur_commit_specify_mtr(&node->pcur, &mtr);
|
btr_pcur_commit_specify_mtr(&node->pcur, &mtr);
|
||||||
@@ -268,21 +268,32 @@ row_undo_ins_remove_sec_low(
|
|||||||
pcur.btr_cur.page_cur.index = index;
|
pcur.btr_cur.page_cur.index = index;
|
||||||
row_mtr_start(&mtr, index, !modify_leaf);
|
row_mtr_start(&mtr, index, !modify_leaf);
|
||||||
|
|
||||||
if (modify_leaf) {
|
|
||||||
mode = BTR_MODIFY_LEAF_ALREADY_LATCHED;
|
|
||||||
mtr_s_lock_index(index, &mtr);
|
|
||||||
} else {
|
|
||||||
ut_ad(mode == BTR_PURGE_TREE);
|
|
||||||
mtr_sx_lock_index(index, &mtr);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (index->is_spatial()) {
|
if (index->is_spatial()) {
|
||||||
mode = modify_leaf
|
mode = modify_leaf
|
||||||
? btr_latch_mode(BTR_MODIFY_LEAF_ALREADY_LATCHED
|
? btr_latch_mode(BTR_MODIFY_LEAF
|
||||||
| BTR_RTREE_DELETE_MARK
|
| BTR_RTREE_DELETE_MARK
|
||||||
| BTR_RTREE_UNDO_INS)
|
| BTR_RTREE_UNDO_INS)
|
||||||
: btr_latch_mode(BTR_PURGE_TREE | BTR_RTREE_UNDO_INS);
|
: btr_latch_mode(BTR_PURGE_TREE | BTR_RTREE_UNDO_INS);
|
||||||
btr_pcur_get_btr_cur(&pcur)->thr = thr;
|
btr_pcur_get_btr_cur(&pcur)->thr = thr;
|
||||||
|
if (rtr_search(entry, mode, &pcur, &mtr)) {
|
||||||
|
goto func_exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rec_get_deleted_flag(
|
||||||
|
btr_pcur_get_rec(&pcur),
|
||||||
|
dict_table_is_comp(index->table))) {
|
||||||
|
ib::error() << "Record found in index " << index->name
|
||||||
|
<< " is deleted marked on insert rollback.";
|
||||||
|
ut_ad(0);
|
||||||
|
}
|
||||||
|
goto found;
|
||||||
|
} else if (modify_leaf) {
|
||||||
|
mode = BTR_MODIFY_LEAF_ALREADY_LATCHED;
|
||||||
|
mtr_s_lock_index(index, &mtr);
|
||||||
|
} else {
|
||||||
|
ut_ad(mode == BTR_PURGE_TREE);
|
||||||
|
mode = BTR_PURGE_TREE_ALREADY_LATCHED;
|
||||||
|
mtr_x_lock_index(index, &mtr);
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (row_search_index_entry(entry, mode, &pcur, &mtr)) {
|
switch (row_search_index_entry(entry, mode, &pcur, &mtr)) {
|
||||||
@@ -295,15 +306,7 @@ row_undo_ins_remove_sec_low(
|
|||||||
case ROW_NOT_FOUND:
|
case ROW_NOT_FOUND:
|
||||||
break;
|
break;
|
||||||
case ROW_FOUND:
|
case ROW_FOUND:
|
||||||
if (dict_index_is_spatial(index)
|
found:
|
||||||
&& rec_get_deleted_flag(
|
|
||||||
btr_pcur_get_rec(&pcur),
|
|
||||||
dict_table_is_comp(index->table))) {
|
|
||||||
ib::error() << "Record found in index " << index->name
|
|
||||||
<< " is deleted marked on insert rollback.";
|
|
||||||
ut_ad(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
btr_cur_t* btr_cur = btr_pcur_get_btr_cur(&pcur);
|
btr_cur_t* btr_cur = btr_pcur_get_btr_cur(&pcur);
|
||||||
|
|
||||||
if (modify_leaf) {
|
if (modify_leaf) {
|
||||||
@@ -318,6 +321,7 @@ row_undo_ins_remove_sec_low(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func_exit:
|
||||||
btr_pcur_close(&pcur);
|
btr_pcur_close(&pcur);
|
||||||
mtr_commit(&mtr);
|
mtr_commit(&mtr);
|
||||||
|
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
|
|
||||||
Copyright (c) 1997, 2017, Oracle and/or its affiliates. All Rights Reserved.
|
Copyright (c) 1997, 2017, Oracle and/or its affiliates. All Rights Reserved.
|
||||||
Copyright (c) 2017, 2022, MariaDB Corporation.
|
Copyright (c) 2017, 2023, MariaDB Corporation.
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify it under
|
This program is free software; you can redistribute it and/or modify it under
|
||||||
the terms of the GNU General Public License as published by the Free Software
|
the terms of the GNU General Public License as published by the Free Software
|
||||||
@@ -133,8 +133,7 @@ row_undo_mod_clust_low(
|
|||||||
&& node->ref == &trx_undo_metadata
|
&& node->ref == &trx_undo_metadata
|
||||||
&& btr_cur_get_index(btr_cur)->table->instant
|
&& btr_cur_get_index(btr_cur)->table->instant
|
||||||
&& node->update->info_bits == REC_INFO_METADATA_ADD) {
|
&& node->update->info_bits == REC_INFO_METADATA_ADD) {
|
||||||
err = btr_reset_instant(*btr_cur_get_index(btr_cur),
|
btr_reset_instant(*btr_cur->index(), false, mtr);
|
||||||
false, mtr);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -490,7 +489,6 @@ row_undo_mod_del_mark_or_remove_sec_low(
|
|||||||
dberr_t err = DB_SUCCESS;
|
dberr_t err = DB_SUCCESS;
|
||||||
mtr_t mtr;
|
mtr_t mtr;
|
||||||
mtr_t mtr_vers;
|
mtr_t mtr_vers;
|
||||||
row_search_result search_result;
|
|
||||||
const bool modify_leaf = mode == BTR_MODIFY_LEAF;
|
const bool modify_leaf = mode == BTR_MODIFY_LEAF;
|
||||||
|
|
||||||
row_mtr_start(&mtr, index, !modify_leaf);
|
row_mtr_start(&mtr, index, !modify_leaf);
|
||||||
@@ -505,6 +503,11 @@ row_undo_mod_del_mark_or_remove_sec_low(
|
|||||||
| BTR_RTREE_UNDO_INS)
|
| BTR_RTREE_UNDO_INS)
|
||||||
: btr_latch_mode(BTR_PURGE_TREE | BTR_RTREE_UNDO_INS);
|
: btr_latch_mode(BTR_PURGE_TREE | BTR_RTREE_UNDO_INS);
|
||||||
btr_cur->thr = thr;
|
btr_cur->thr = thr;
|
||||||
|
if (UNIV_LIKELY(!rtr_search(entry, mode, &pcur, &mtr))) {
|
||||||
|
goto found;
|
||||||
|
} else {
|
||||||
|
goto func_exit;
|
||||||
|
}
|
||||||
} else if (!index->is_committed()) {
|
} else if (!index->is_committed()) {
|
||||||
/* The index->online_status may change if the index is
|
/* The index->online_status may change if the index is
|
||||||
or was being created online, but not committed yet. It
|
or was being created online, but not committed yet. It
|
||||||
@@ -514,7 +517,8 @@ row_undo_mod_del_mark_or_remove_sec_low(
|
|||||||
mtr_s_lock_index(index, &mtr);
|
mtr_s_lock_index(index, &mtr);
|
||||||
} else {
|
} else {
|
||||||
ut_ad(mode == BTR_PURGE_TREE);
|
ut_ad(mode == BTR_PURGE_TREE);
|
||||||
mtr_sx_lock_index(index, &mtr);
|
mode = BTR_PURGE_TREE_ALREADY_LATCHED;
|
||||||
|
mtr_x_lock_index(index, &mtr);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* For secondary indexes,
|
/* For secondary indexes,
|
||||||
@@ -523,9 +527,8 @@ row_undo_mod_del_mark_or_remove_sec_low(
|
|||||||
ut_ad(!dict_index_is_online_ddl(index));
|
ut_ad(!dict_index_is_online_ddl(index));
|
||||||
}
|
}
|
||||||
|
|
||||||
search_result = row_search_index_entry(entry, mode, &pcur, &mtr);
|
switch (UNIV_EXPECT(row_search_index_entry(entry, mode, &pcur, &mtr),
|
||||||
|
ROW_FOUND)) {
|
||||||
switch (UNIV_EXPECT(search_result, ROW_FOUND)) {
|
|
||||||
case ROW_NOT_FOUND:
|
case ROW_NOT_FOUND:
|
||||||
/* In crash recovery, the secondary index record may
|
/* In crash recovery, the secondary index record may
|
||||||
be missing if the UPDATE did not have time to insert
|
be missing if the UPDATE did not have time to insert
|
||||||
@@ -547,6 +550,7 @@ row_undo_mod_del_mark_or_remove_sec_low(
|
|||||||
ut_error;
|
ut_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
found:
|
||||||
/* We should remove the index record if no prior version of the row,
|
/* We should remove the index record if no prior version of the row,
|
||||||
which cannot be purged yet, requires its existence. If some requires,
|
which cannot be purged yet, requires its existence. If some requires,
|
||||||
we should delete mark the record. */
|
we should delete mark the record. */
|
||||||
@@ -665,13 +669,12 @@ row_undo_mod_del_unmark_sec_and_undo_update(
|
|||||||
trx_t* trx = thr_get_trx(thr);
|
trx_t* trx = thr_get_trx(thr);
|
||||||
const ulint flags
|
const ulint flags
|
||||||
= BTR_KEEP_SYS_FLAG | BTR_NO_LOCKING_FLAG;
|
= BTR_KEEP_SYS_FLAG | BTR_NO_LOCKING_FLAG;
|
||||||
row_search_result search_result;
|
|
||||||
const auto orig_mode = mode;
|
const auto orig_mode = mode;
|
||||||
|
|
||||||
pcur.btr_cur.page_cur.index = index;
|
pcur.btr_cur.page_cur.index = index;
|
||||||
ut_ad(trx->id != 0);
|
ut_ad(trx->id != 0);
|
||||||
|
|
||||||
if (dict_index_is_spatial(index)) {
|
if (index->is_spatial()) {
|
||||||
/* FIXME: Currently we do a 2-pass search for the undo
|
/* FIXME: Currently we do a 2-pass search for the undo
|
||||||
due to avoid undel-mark a wrong rec in rolling back in
|
due to avoid undel-mark a wrong rec in rolling back in
|
||||||
partial update. Later, we could log some info in
|
partial update. Later, we could log some info in
|
||||||
@@ -686,9 +689,22 @@ try_again:
|
|||||||
|
|
||||||
btr_cur->thr = thr;
|
btr_cur->thr = thr;
|
||||||
|
|
||||||
search_result = row_search_index_entry(entry, mode, &pcur, &mtr);
|
if (index->is_spatial()) {
|
||||||
|
if (!rtr_search(entry, mode, &pcur, &mtr)) {
|
||||||
|
goto found;
|
||||||
|
}
|
||||||
|
|
||||||
switch (search_result) {
|
if (mode != orig_mode && btr_cur->rtr_info->fd_del) {
|
||||||
|
mode = orig_mode;
|
||||||
|
btr_pcur_close(&pcur);
|
||||||
|
mtr.commit();
|
||||||
|
goto try_again;
|
||||||
|
}
|
||||||
|
|
||||||
|
goto not_found;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (row_search_index_entry(entry, mode, &pcur, &mtr)) {
|
||||||
mem_heap_t* heap;
|
mem_heap_t* heap;
|
||||||
mem_heap_t* offsets_heap;
|
mem_heap_t* offsets_heap;
|
||||||
rec_offs* offsets;
|
rec_offs* offsets;
|
||||||
@@ -699,17 +715,7 @@ try_again:
|
|||||||
flags BTR_INSERT, BTR_DELETE, or BTR_DELETE_MARK. */
|
flags BTR_INSERT, BTR_DELETE, or BTR_DELETE_MARK. */
|
||||||
ut_error;
|
ut_error;
|
||||||
case ROW_NOT_FOUND:
|
case ROW_NOT_FOUND:
|
||||||
/* For spatial index, if first search didn't find an
|
not_found:
|
||||||
undel-marked rec, try to find a del-marked rec. */
|
|
||||||
if (dict_index_is_spatial(index) && btr_cur->rtr_info->fd_del) {
|
|
||||||
if (mode != orig_mode) {
|
|
||||||
mode = orig_mode;
|
|
||||||
btr_pcur_close(&pcur);
|
|
||||||
mtr_commit(&mtr);
|
|
||||||
goto try_again;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (btr_cur->up_match >= dict_index_get_n_unique(index)
|
if (btr_cur->up_match >= dict_index_get_n_unique(index)
|
||||||
|| btr_cur->low_match >= dict_index_get_n_unique(index)) {
|
|| btr_cur->low_match >= dict_index_get_n_unique(index)) {
|
||||||
ib::warn() << "Record in index " << index->name
|
ib::warn() << "Record in index " << index->name
|
||||||
@@ -767,6 +773,7 @@ try_again:
|
|||||||
|
|
||||||
break;
|
break;
|
||||||
case ROW_FOUND:
|
case ROW_FOUND:
|
||||||
|
found:
|
||||||
btr_rec_set_deleted<false>(btr_cur_get_block(btr_cur),
|
btr_rec_set_deleted<false>(btr_cur_get_block(btr_cur),
|
||||||
btr_cur_get_rec(btr_cur), &mtr);
|
btr_cur_get_rec(btr_cur), &mtr);
|
||||||
heap = mem_heap_create(
|
heap = mem_heap_create(
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
|
|
||||||
Copyright (c) 1996, 2017, Oracle and/or its affiliates. All Rights Reserved.
|
Copyright (c) 1996, 2017, Oracle and/or its affiliates. All Rights Reserved.
|
||||||
Copyright (c) 2015, 2022, MariaDB Corporation.
|
Copyright (c) 2015, 2023, MariaDB Corporation.
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify it under
|
This program is free software; you can redistribute it and/or modify it under
|
||||||
the terms of the GNU General Public License as published by the Free Software
|
the terms of the GNU General Public License as published by the Free Software
|
||||||
@@ -1832,12 +1832,10 @@ row_upd_sec_index_entry(
|
|||||||
que_thr_t* thr) /*!< in: query thread */
|
que_thr_t* thr) /*!< in: query thread */
|
||||||
{
|
{
|
||||||
mtr_t mtr;
|
mtr_t mtr;
|
||||||
const rec_t* rec;
|
|
||||||
btr_pcur_t pcur;
|
btr_pcur_t pcur;
|
||||||
mem_heap_t* heap;
|
mem_heap_t* heap;
|
||||||
dtuple_t* entry;
|
dtuple_t* entry;
|
||||||
dict_index_t* index;
|
dict_index_t* index;
|
||||||
btr_cur_t* btr_cur;
|
|
||||||
dberr_t err = DB_SUCCESS;
|
dberr_t err = DB_SUCCESS;
|
||||||
trx_t* trx = thr_get_trx(thr);
|
trx_t* trx = thr_get_trx(thr);
|
||||||
btr_latch_mode mode;
|
btr_latch_mode mode;
|
||||||
@@ -1876,10 +1874,6 @@ row_upd_sec_index_entry(
|
|||||||
case SRV_TMP_SPACE_ID:
|
case SRV_TMP_SPACE_ID:
|
||||||
mtr.set_log_mode(MTR_LOG_NO_REDO);
|
mtr.set_log_mode(MTR_LOG_NO_REDO);
|
||||||
flags = BTR_NO_LOCKING_FLAG;
|
flags = BTR_NO_LOCKING_FLAG;
|
||||||
if (index->is_spatial()) {
|
|
||||||
mode = btr_latch_mode(BTR_MODIFY_LEAF
|
|
||||||
| BTR_RTREE_DELETE_MARK);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
index->set_modified(mtr);
|
index->set_modified(mtr);
|
||||||
@@ -1888,26 +1882,35 @@ row_upd_sec_index_entry(
|
|||||||
flags = index->table->no_rollback() ? BTR_NO_ROLLBACK : 0;
|
flags = index->table->no_rollback() ? BTR_NO_ROLLBACK : 0;
|
||||||
/* We can only buffer delete-mark operations if there
|
/* We can only buffer delete-mark operations if there
|
||||||
are no foreign key constraints referring to the index. */
|
are no foreign key constraints referring to the index. */
|
||||||
mode = index->is_spatial()
|
if (!referenced) {
|
||||||
? btr_latch_mode(BTR_MODIFY_LEAF
|
mode = BTR_DELETE_MARK_LEAF;
|
||||||
| BTR_RTREE_DELETE_MARK)
|
}
|
||||||
: referenced
|
|
||||||
? BTR_MODIFY_LEAF : BTR_DELETE_MARK_LEAF;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set the query thread, so that ibuf_insert_low() will be
|
/* Set the query thread, so that ibuf_insert_low() will be
|
||||||
able to invoke thd_get_trx(). */
|
able to invoke thd_get_trx(). */
|
||||||
btr_pcur_get_btr_cur(&pcur)->thr = thr;
|
pcur.btr_cur.thr = thr;
|
||||||
pcur.btr_cur.page_cur.index = index;
|
pcur.btr_cur.page_cur.index = index;
|
||||||
|
|
||||||
|
if (index->is_spatial()) {
|
||||||
|
mode = btr_latch_mode(BTR_MODIFY_LEAF | BTR_RTREE_DELETE_MARK);
|
||||||
|
if (UNIV_LIKELY(!rtr_search(entry, mode, &pcur, &mtr))) {
|
||||||
|
goto found;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pcur.btr_cur.rtr_info->fd_del) {
|
||||||
|
/* We found the record, but a delete marked */
|
||||||
|
goto close;
|
||||||
|
}
|
||||||
|
|
||||||
|
goto not_found;
|
||||||
|
}
|
||||||
|
|
||||||
search_result = row_search_index_entry(entry, mode, &pcur, &mtr);
|
search_result = row_search_index_entry(entry, mode, &pcur, &mtr);
|
||||||
|
|
||||||
btr_cur = btr_pcur_get_btr_cur(&pcur);
|
|
||||||
|
|
||||||
rec = btr_cur_get_rec(btr_cur);
|
|
||||||
|
|
||||||
switch (search_result) {
|
switch (search_result) {
|
||||||
|
const rec_t* rec;
|
||||||
case ROW_NOT_DELETED_REF: /* should only occur for BTR_DELETE */
|
case ROW_NOT_DELETED_REF: /* should only occur for BTR_DELETE */
|
||||||
ut_error;
|
ut_error;
|
||||||
break;
|
break;
|
||||||
@@ -1916,11 +1919,8 @@ row_upd_sec_index_entry(
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case ROW_NOT_FOUND:
|
case ROW_NOT_FOUND:
|
||||||
if (dict_index_is_spatial(index) && btr_cur->rtr_info->fd_del) {
|
not_found:
|
||||||
/* We found the record, but a delete marked */
|
rec = btr_pcur_get_rec(&pcur);
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
ib::error()
|
ib::error()
|
||||||
<< "Record in index " << index->name
|
<< "Record in index " << index->name
|
||||||
<< " of table " << index->table->name
|
<< " of table " << index->table->name
|
||||||
@@ -1934,7 +1934,9 @@ row_upd_sec_index_entry(
|
|||||||
#endif /* UNIV_DEBUG */
|
#endif /* UNIV_DEBUG */
|
||||||
break;
|
break;
|
||||||
case ROW_FOUND:
|
case ROW_FOUND:
|
||||||
|
found:
|
||||||
ut_ad(err == DB_SUCCESS);
|
ut_ad(err == DB_SUCCESS);
|
||||||
|
rec = btr_pcur_get_rec(&pcur);
|
||||||
|
|
||||||
/* Delete mark the old index record; it can already be
|
/* Delete mark the old index record; it can already be
|
||||||
delete marked if we return after a lock wait in
|
delete marked if we return after a lock wait in
|
||||||
@@ -1943,14 +1945,14 @@ row_upd_sec_index_entry(
|
|||||||
rec, dict_table_is_comp(index->table))) {
|
rec, dict_table_is_comp(index->table))) {
|
||||||
err = lock_sec_rec_modify_check_and_lock(
|
err = lock_sec_rec_modify_check_and_lock(
|
||||||
flags,
|
flags,
|
||||||
btr_cur_get_block(btr_cur),
|
btr_pcur_get_block(&pcur),
|
||||||
btr_cur_get_rec(btr_cur), index, thr, &mtr);
|
btr_pcur_get_rec(&pcur), index, thr, &mtr);
|
||||||
if (err != DB_SUCCESS) {
|
if (err != DB_SUCCESS) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
btr_rec_set_deleted<true>(btr_cur_get_block(btr_cur),
|
btr_rec_set_deleted<true>(btr_pcur_get_block(&pcur),
|
||||||
btr_cur_get_rec(btr_cur),
|
btr_pcur_get_rec(&pcur),
|
||||||
&mtr);
|
&mtr);
|
||||||
#ifdef WITH_WSREP
|
#ifdef WITH_WSREP
|
||||||
if (!referenced && foreign
|
if (!referenced && foreign
|
||||||
@@ -2009,6 +2011,7 @@ row_upd_sec_index_entry(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
close:
|
||||||
btr_pcur_close(&pcur);
|
btr_pcur_close(&pcur);
|
||||||
mtr_commit(&mtr);
|
mtr_commit(&mtr);
|
||||||
|
|
||||||
|
@@ -426,7 +426,6 @@ static dberr_t trx_purge_free_segment(trx_rseg_t *rseg, fil_addr_t hdr_addr)
|
|||||||
block->fix();
|
block->fix();
|
||||||
mtr.commit();
|
mtr.commit();
|
||||||
mtr.start();
|
mtr.start();
|
||||||
mtr.flag_modified();
|
|
||||||
rseg->latch.wr_lock(SRW_LOCK_CALL);
|
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();
|
||||||
|
@@ -979,10 +979,8 @@ int ha_spider::reset()
|
|||||||
result_list.snap_direct_aggregate = FALSE;
|
result_list.snap_direct_aggregate = FALSE;
|
||||||
result_list.direct_distinct = FALSE;
|
result_list.direct_distinct = FALSE;
|
||||||
store_error_num = 0;
|
store_error_num = 0;
|
||||||
if (
|
if (wide_handler)
|
||||||
wide_handler &&
|
{
|
||||||
wide_handler->sql_command != SQLCOM_END
|
|
||||||
) {
|
|
||||||
wide_handler->sql_command = SQLCOM_END;
|
wide_handler->sql_command = SQLCOM_END;
|
||||||
wide_handler->between_flg = FALSE;
|
wide_handler->between_flg = FALSE;
|
||||||
wide_handler->idx_bitmap_is_set = FALSE;
|
wide_handler->idx_bitmap_is_set = FALSE;
|
||||||
|
44
storage/spider/mysql-test/spider/bugfix/r/mdev_30191.result
Normal file
44
storage/spider/mysql-test/spider/bugfix/r/mdev_30191.result
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
#
|
||||||
|
# MDEV-30191 SIGSEGV & heap-use-after-free in spider_db_print_item_type, SIGABRT in __cxa_pure_virtual/spider_db_print_item_type, Got error 128 "Out of memory in engine", 56/112 memory not freed, and Assertion `fixed()' failed in Item_sp_variable::val_str on SP call
|
||||||
|
#
|
||||||
|
for master_1
|
||||||
|
for child2
|
||||||
|
child2_1
|
||||||
|
child2_2
|
||||||
|
child2_3
|
||||||
|
for child3
|
||||||
|
connection child2_1;
|
||||||
|
CREATE DATABASE auto_test_remote;
|
||||||
|
USE auto_test_remote;
|
||||||
|
CREATE TABLE tbl_a (c INT);
|
||||||
|
connection master_1;
|
||||||
|
CREATE DATABASE auto_test_local;
|
||||||
|
USE auto_test_local;
|
||||||
|
CREATE TABLE tbl_a (
|
||||||
|
c INT
|
||||||
|
) ENGINE=Spider DEFAULT CHARSET=utf8 COMMENT='table "tbl_a", srv "s_2_1"';
|
||||||
|
CREATE TABLE tbl_b (c INT);
|
||||||
|
CREATE PROCEDURE sp() BEGIN
|
||||||
|
DECLARE v1 DATE;
|
||||||
|
WHILE EXISTS (SELECT 1 FROM tbl_a WHERE c>v1 AND c<=v1) DO
|
||||||
|
SELECT 1;
|
||||||
|
END WHILE;
|
||||||
|
WHILE EXISTS (SELECT 1
|
||||||
|
FROM tbl_a
|
||||||
|
WHERE c<v1 AND EXISTS (SELECT 1
|
||||||
|
FROM tbl_b
|
||||||
|
WHERE tbl_a.c=tbl_b.c)) DO
|
||||||
|
SELECT 1;
|
||||||
|
END WHILE;
|
||||||
|
END $$
|
||||||
|
CALL sp();
|
||||||
|
connection master_1;
|
||||||
|
DROP DATABASE IF EXISTS auto_test_local;
|
||||||
|
connection child2_1;
|
||||||
|
DROP DATABASE IF EXISTS auto_test_remote;
|
||||||
|
for master_1
|
||||||
|
for child2
|
||||||
|
child2_1
|
||||||
|
child2_2
|
||||||
|
child2_3
|
||||||
|
for child3
|
3
storage/spider/mysql-test/spider/bugfix/t/mdev_30191.cnf
Normal file
3
storage/spider/mysql-test/spider/bugfix/t/mdev_30191.cnf
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
!include include/default_mysqld.cnf
|
||||||
|
!include ../my_1_1.cnf
|
||||||
|
!include ../my_2_1.cnf
|
51
storage/spider/mysql-test/spider/bugfix/t/mdev_30191.test
Normal file
51
storage/spider/mysql-test/spider/bugfix/t/mdev_30191.test
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
--echo #
|
||||||
|
--echo # MDEV-30191 SIGSEGV & heap-use-after-free in spider_db_print_item_type, SIGABRT in __cxa_pure_virtual/spider_db_print_item_type, Got error 128 "Out of memory in engine", 56/112 memory not freed, and Assertion `fixed()' failed in Item_sp_variable::val_str on SP call
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
--disable_query_log
|
||||||
|
--disable_result_log
|
||||||
|
--source ../../t/test_init.inc
|
||||||
|
--enable_result_log
|
||||||
|
--enable_query_log
|
||||||
|
|
||||||
|
--connection child2_1
|
||||||
|
CREATE DATABASE auto_test_remote;
|
||||||
|
USE auto_test_remote;
|
||||||
|
CREATE TABLE tbl_a (c INT);
|
||||||
|
|
||||||
|
--connection master_1
|
||||||
|
CREATE DATABASE auto_test_local;
|
||||||
|
USE auto_test_local;
|
||||||
|
|
||||||
|
eval CREATE TABLE tbl_a (
|
||||||
|
c INT
|
||||||
|
) $MASTER_1_ENGINE $MASTER_1_CHARSET COMMENT='table "tbl_a", srv "s_2_1"';
|
||||||
|
CREATE TABLE tbl_b (c INT);
|
||||||
|
|
||||||
|
--delimiter $$
|
||||||
|
CREATE PROCEDURE sp() BEGIN
|
||||||
|
DECLARE v1 DATE;
|
||||||
|
WHILE EXISTS (SELECT 1 FROM tbl_a WHERE c>v1 AND c<=v1) DO
|
||||||
|
SELECT 1;
|
||||||
|
END WHILE;
|
||||||
|
WHILE EXISTS (SELECT 1
|
||||||
|
FROM tbl_a
|
||||||
|
WHERE c<v1 AND EXISTS (SELECT 1
|
||||||
|
FROM tbl_b
|
||||||
|
WHERE tbl_a.c=tbl_b.c)) DO
|
||||||
|
SELECT 1;
|
||||||
|
END WHILE;
|
||||||
|
END $$
|
||||||
|
--delimiter ;
|
||||||
|
CALL sp();
|
||||||
|
|
||||||
|
--connection master_1
|
||||||
|
DROP DATABASE IF EXISTS auto_test_local;
|
||||||
|
--connection child2_1
|
||||||
|
DROP DATABASE IF EXISTS auto_test_remote;
|
||||||
|
|
||||||
|
--disable_query_log
|
||||||
|
--disable_result_log
|
||||||
|
--source ../t/test_deinit.inc
|
||||||
|
--enable_query_log
|
||||||
|
--enable_result_log
|
Reference in New Issue
Block a user