1
0
mirror of https://github.com/MariaDB/server.git synced 2026-10-23 18:49:29 +03:00
Fix InnoDB_backup::log_track() hang
This commit is contained in:
Marko Mäkelä
2026-10-01 16:21:31 +03:00
parent 5cd0cb308b
commit ea087a30f0
7 changed files with 160 additions and 30 deletions

View File

@@ -1,6 +1,6 @@
--- backup_innodb.result
+++ backup_innodb,debug.result
@@ -26,8 +26,10 @@
@@ -25,8 +25,10 @@
BEGIN;
DELETE FROM t;
connect backup,localhost,root;
@@ -11,10 +11,36 @@
connect rename,localhost,root;
RENAME TABLE rt TO rtt;
CREATE TABLE rt(a INT PRIMARY KEY) ENGINE=InnoDB;
@@ -35,6 +37,7 @@
@@ -34,6 +36,33 @@
disconnect rename;
connection default;
INSERT INTO t(a) SELECT * FROM seq_1_to_30000;
INSERT INTO t SELECT seq a, '' b FROM seq_1_to_30000;
+SET DEBUG_SYNC='now SIGNAL resume';
+connection backup;
+Got one of the listed errors
+disconnect backup;
+connection default;
+DROP TABLE t, rt, rtt;
+CREATE TABLE dt(a INT PRIMARY KEY, b CHAR(255)) ENGINE=InnoDB
+SELECT seq a, '' b FROM seq_1_to_100000;
+CREATE TABLE rt(a INT PRIMARY KEY) ENGINE=InnoDB;
+SET GLOBAL innodb_log_checkpoint_now=ON;
+CREATE TABLE t(a INT PRIMARY KEY, b CHAR(255), INDEX(b)) ENGINE=INNODB
+SELECT 1 a, '' b;
+BEGIN;
+DELETE FROM t;
+connect backup,localhost,root;
+SET DEBUG_SYNC='innodb_backup_start SIGNAL start WAIT_FOR resume';
+BACKUP SERVER TO 'target_directory' 4 CONCURRENT;
+connection default;
+SET DEBUG_SYNC='now WAIT_FOR start';
+connect rename,localhost,root;
+RENAME TABLE rt TO rtt;
+CREATE TABLE rt(a INT PRIMARY KEY) ENGINE=InnoDB;
+DROP TABLE dt;
+disconnect rename;
+connection default;
+INSERT INTO t SELECT seq a, '' b FROM seq_1_to_30000;
+SET DEBUG_SYNC='now SIGNAL resume';
connection backup;
disconnect backup;

View File

@@ -6,10 +6,9 @@ CREATE TABLE dt(a INT PRIMARY KEY, b CHAR(255)) ENGINE=InnoDB
SELECT seq a, '' b FROM seq_1_to_100000;
CREATE TABLE rt(a INT PRIMARY KEY) ENGINE=InnoDB;
SET GLOBAL innodb_log_checkpoint_now=ON;
CREATE TABLE t(a INT PRIMARY KEY, b CHAR(255) DEFAULT '' NOT NULL, INDEX(b))
ENGINE=INNODB;
CREATE TABLE t(a INT PRIMARY KEY, b CHAR(255), INDEX(b))ENGINE=INNODB;
BEGIN;
INSERT INTO t SET a=1;
INSERT INTO t SET a=1, b='';
BACKUP SERVER TO '$target_directory';
ROLLBACK;
SELECT * FROM t;
@@ -34,7 +33,7 @@ CREATE TABLE rt(a INT PRIMARY KEY) ENGINE=InnoDB;
DROP TABLE dt;
disconnect rename;
connection default;
INSERT INTO t(a) SELECT * FROM seq_1_to_30000;
INSERT INTO t SELECT seq a, '' b FROM seq_1_to_30000;
connection backup;
disconnect backup;
connection default;

View File

@@ -1,6 +1,15 @@
--source include/have_sequence.inc
--source include/have_innodb.inc
--source include/maybe_debug.inc
--let $attempts= 1
if ($have_debug) {
inc $attempts;
--source include/have_debug_sync.inc
--disable_query_log
call mtr.add_suppression("mariadbd.*: Unknown error");
call mtr.add_suppression("mariadbd.*: Can't create file .*mysql/");
--enable_query_log
}
--disable_query_log
call mtr.add_suppression("mariadbd.*: IO Write error:");
@@ -21,10 +30,9 @@ CREATE TABLE rt(a INT PRIMARY KEY) ENGINE=InnoDB;
# instead of recovering it via a FILE_CREATE record.
SET GLOBAL innodb_log_checkpoint_now=ON;
CREATE TABLE t(a INT PRIMARY KEY, b CHAR(255) DEFAULT '' NOT NULL, INDEX(b))
ENGINE=INNODB;
CREATE TABLE t(a INT PRIMARY KEY, b CHAR(255), INDEX(b))ENGINE=INNODB;
BEGIN;
INSERT INTO t SET a=1;
INSERT INTO t SET a=1, b='';
--let $target_directory=/tmp/some_directory$MTR_COMBINATION_ARCHIVED
@@ -38,7 +46,6 @@ INSERT INTO t SET a=1;
--rmdir $target_directory
evalp BACKUP SERVER TO '$target_directory';
--rmdir $target_directory
ROLLBACK;
# BACKUP SERVER will implicitly commit the current transaction
SELECT * FROM t;
@@ -53,9 +60,14 @@ BACKUP SERVER WITH '/bin/false';
--error ER_IO_WRITE_ERROR
BACKUP SERVER WITH 'no-such-command';
BEGIN;
DELETE FROM t;
--write_file $target_directory.empty_file
EOF
BEGIN; DELETE FROM t;
while ($attempts) {
dec $attempts;
--rmdir $target_directory
--connect backup,localhost,root
if ($have_debug) {
SET DEBUG_SYNC='innodb_backup_start SIGNAL start WAIT_FOR resume';
@@ -66,21 +78,50 @@ send_eval BACKUP SERVER TO '$target_directory' 4 CONCURRENT;
if ($have_debug) {
SET DEBUG_SYNC='now WAIT_FOR start';
}
if ($attempts) {
--move_file $target_directory.empty_file $target_directory/mysql
}
--connect rename,localhost,root
RENAME TABLE rt TO rtt;
CREATE TABLE rt(a INT PRIMARY KEY) ENGINE=InnoDB;
DROP TABLE dt;
--disconnect rename
--connection default
INSERT INTO t(a) SELECT * FROM seq_1_to_30000;
INSERT INTO t SELECT seq a, '' b FROM seq_1_to_30000;
if ($have_debug) {
SET DEBUG_SYNC='now SIGNAL resume';
}
if (!$attempts) {
--connection backup
--reap
--disconnect backup
--connection default
ROLLBACK;
}
if ($attempts) {
--connection backup
--error ER_CANT_CREATE_FILE,ER_UNKNOWN_ERROR
--reap
--disconnect backup
--connection default
# Clean up for a retry without a fault injection.
DROP TABLE t, rt, rtt;
CREATE TABLE dt(a INT PRIMARY KEY, b CHAR(255)) ENGINE=InnoDB
SELECT seq a, '' b FROM seq_1_to_100000;
# Create a table that must be copied and renamed during the backup
CREATE TABLE rt(a INT PRIMARY KEY) ENGINE=InnoDB;
# Because log checkpoint will complete before BACKUP SERVER,
# the above CREATE TABLE must lead to copying the data file,
# instead of recovering it via a FILE_CREATE record.
SET GLOBAL innodb_log_checkpoint_now=ON;
CREATE TABLE t(a INT PRIMARY KEY, b CHAR(255), INDEX(b)) ENGINE=INNODB
SELECT 1 a, '' b;
BEGIN; DELETE FROM t;
}
}
--error 0,1
--remove_file $target_directory.empty_file
SELECT * FROM rt;
SELECT * FROM rtt;
SELECT * FROM t;

View File

@@ -1,6 +1,6 @@
--- backup_innodb.result
+++ backup_innodb,debug.result
@@ -26,8 +26,10 @@
@@ -25,8 +25,10 @@
BEGIN;
DELETE FROM t;
connect backup,localhost,root;
@@ -11,10 +11,36 @@
connect rename,localhost,root;
RENAME TABLE rt TO rtt;
CREATE TABLE rt(a INT PRIMARY KEY) ENGINE=InnoDB;
@@ -35,6 +37,7 @@
@@ -34,6 +36,33 @@
disconnect rename;
connection default;
INSERT INTO t(a) SELECT * FROM seq_1_to_30000;
INSERT INTO t SELECT seq a, '' b FROM seq_1_to_30000;
+SET DEBUG_SYNC='now SIGNAL resume';
+connection backup;
+Got one of the listed errors
+disconnect backup;
+connection default;
+DROP TABLE t, rt, rtt;
+CREATE TABLE dt(a INT PRIMARY KEY, b CHAR(255)) ENGINE=InnoDB
+SELECT seq a, '' b FROM seq_1_to_100000;
+CREATE TABLE rt(a INT PRIMARY KEY) ENGINE=InnoDB;
+SET GLOBAL innodb_log_checkpoint_now=ON;
+CREATE TABLE t(a INT PRIMARY KEY, b CHAR(255), INDEX(b)) ENGINE=INNODB
+SELECT 1 a, '' b;
+BEGIN;
+DELETE FROM t;
+connect backup,localhost,root;
+SET DEBUG_SYNC='innodb_backup_start SIGNAL start WAIT_FOR resume';
+BACKUP SERVER TO 'target_directory' 4 CONCURRENT;
+connection default;
+SET DEBUG_SYNC='now WAIT_FOR start';
+connect rename,localhost,root;
+RENAME TABLE rt TO rtt;
+CREATE TABLE rt(a INT PRIMARY KEY) ENGINE=InnoDB;
+DROP TABLE dt;
+disconnect rename;
+connection default;
+INSERT INTO t SELECT seq a, '' b FROM seq_1_to_30000;
+SET DEBUG_SYNC='now SIGNAL resume';
connection backup;
disconnect backup;

View File

@@ -6,10 +6,9 @@ CREATE TABLE dt(a INT PRIMARY KEY, b CHAR(255)) ENGINE=InnoDB
SELECT seq a, '' b FROM seq_1_to_100000;
CREATE TABLE rt(a INT PRIMARY KEY) ENGINE=InnoDB;
SET GLOBAL innodb_log_checkpoint_now=ON;
CREATE TABLE t(a INT PRIMARY KEY, b CHAR(255) DEFAULT '' NOT NULL, INDEX(b))
ENGINE=INNODB;
CREATE TABLE t(a INT PRIMARY KEY, b CHAR(255), INDEX(b))ENGINE=INNODB;
BEGIN;
INSERT INTO t SET a=1;
INSERT INTO t SET a=1, b='';
BACKUP SERVER TO '$target_directory';
ROLLBACK;
SELECT * FROM t;
@@ -34,7 +33,7 @@ CREATE TABLE rt(a INT PRIMARY KEY) ENGINE=InnoDB;
DROP TABLE dt;
disconnect rename;
connection default;
INSERT INTO t(a) SELECT * FROM seq_1_to_30000;
INSERT INTO t SELECT seq a, '' b FROM seq_1_to_30000;
connection backup;
disconnect backup;
connection default;

View File

@@ -6,10 +6,9 @@ CREATE TABLE dt(a INT PRIMARY KEY, b CHAR(255)) ENGINE=InnoDB
SELECT seq a, '' b FROM seq_1_to_100000;
CREATE TABLE rt(a INT PRIMARY KEY) ENGINE=InnoDB;
SET GLOBAL innodb_log_checkpoint_now=ON;
CREATE TABLE t(a INT PRIMARY KEY, b CHAR(255) DEFAULT '' NOT NULL, INDEX(b))
ENGINE=INNODB;
CREATE TABLE t(a INT PRIMARY KEY, b CHAR(255), INDEX(b))ENGINE=INNODB;
BEGIN;
INSERT INTO t SET a=1;
INSERT INTO t SET a=1, b='';
BACKUP SERVER TO '$target_directory';
ROLLBACK;
SELECT * FROM t;
@@ -36,7 +35,33 @@ CREATE TABLE rt(a INT PRIMARY KEY) ENGINE=InnoDB;
DROP TABLE dt;
disconnect rename;
connection default;
INSERT INTO t(a) SELECT * FROM seq_1_to_30000;
INSERT INTO t SELECT seq a, '' b FROM seq_1_to_30000;
SET DEBUG_SYNC='now SIGNAL resume';
connection backup;
Got one of the listed errors
disconnect backup;
connection default;
DROP TABLE t, rt, rtt;
CREATE TABLE dt(a INT PRIMARY KEY, b CHAR(255)) ENGINE=InnoDB
SELECT seq a, '' b FROM seq_1_to_100000;
CREATE TABLE rt(a INT PRIMARY KEY) ENGINE=InnoDB;
SET GLOBAL innodb_log_checkpoint_now=ON;
CREATE TABLE t(a INT PRIMARY KEY, b CHAR(255), INDEX(b)) ENGINE=INNODB
SELECT 1 a, '' b;
BEGIN;
DELETE FROM t;
connect backup,localhost,root;
SET DEBUG_SYNC='innodb_backup_start SIGNAL start WAIT_FOR resume';
BACKUP SERVER TO 'target_directory' 4 CONCURRENT;
connection default;
SET DEBUG_SYNC='now WAIT_FOR start';
connect rename,localhost,root;
RENAME TABLE rt TO rtt;
CREATE TABLE rt(a INT PRIMARY KEY) ENGINE=InnoDB;
DROP TABLE dt;
disconnect rename;
connection default;
INSERT INTO t SELECT seq a, '' b FROM seq_1_to_30000;
SET DEBUG_SYNC='now SIGNAL resume';
connection backup;
disconnect backup;

View File

@@ -687,6 +687,8 @@ public:
{
/* An error was flagged. */
size= size_t(-1);
/* Interrupt log_track(). */
ctx.last_lsn= 0;
my_error(ER_UNKNOWN_ERROR, MYF(0));
done:
mutex.wr_unlock();
@@ -702,6 +704,8 @@ public:
queue.pop_back();
mutex.wr_unlock();
int res= int(std::min(size_t{std::numeric_limits<int>::max()}, size - 1));
if (size > non_log_files)
{
log_sys.latch.rd_lock();
@@ -711,7 +715,7 @@ public:
/* Wait for checkpoint_complete(). */
buf_flush_sync_batch(id_limit, true);
if (replicate(id_limit, target, sink, id_limit < first))
return -1;
res= -1;
}
else
{
@@ -725,16 +729,26 @@ public:
mysql_mutex_unlock(&fil_system.mutex);
if (acquired)
if (int res= backup_space(target, *space, sink, backup_name,
if (int err= backup_space(target, *space, sink, backup_name,
uint32_t(id_limit >> 32)))
return res;
{
ut_ad(err < 0);
res= err;
}
}
else
mysql_mutex_unlock(&fil_system.mutex);
}
ut_ad(size > 0);
return int(std::min(size_t{std::numeric_limits<int>::max()}, size - 1));
if (UNIV_UNLIKELY(res < 0))
{
/* Interrupt log_track(). */
mutex.wr_lock();
ctx.last_lsn= 0;
mutex.wr_unlock();
}
return res;
}
/**