mariadb/mysql-test/suite/innodb/t/dml_purge.test

84 lines
2.5 KiB
Text
Raw Permalink Normal View History

2017-08-15 17:18:55 +03:00
--source include/innodb_page_size.inc
SET @save_stats_persistent = @@GLOBAL.innodb_stats_persistent;
SET GLOBAL innodb_stats_persistent = 0;
2017-08-15 17:18:55 +03:00
let INNODB_PAGE_SIZE=`select @@innodb_page_size`;
let MYSQLD_DATADIR=`select @@datadir`;
--echo #
--echo # MDEV-12288 Reset DB_TRX_ID when the history is removed,
--echo # to speed up MVCC
--echo #
CREATE TABLE t1(a INT PRIMARY KEY, b INT NOT NULL)
ROW_FORMAT=REDUNDANT ENGINE=InnoDB;
MDEV-30671 InnoDB undo log truncation fails to wait for purge of history It is not safe to invoke trx_purge_free_segment() or execute innodb_undo_log_truncate=ON before all undo log records in the rollback segment has been processed. A prominent failure that would occur due to premature freeing of undo log pages is that trx_undo_get_undo_rec() would crash when trying to copy an undo log record to fetch the previous version of a record. If trx_undo_get_undo_rec() was not invoked in the unlucky time frame, then the symptom would be that some committed transaction history is never removed. This would be detected by CHECK TABLE...EXTENDED that was impleented in commit ab0190101b0587e0e03b2d75a967050b9a85fd1b. Such a garbage collection leak should be possible even when using innodb_undo_log_truncate=OFF, just involving trx_purge_free_segment(). trx_rseg_t::needs_purge: Change the type from Boolean to a transaction identifier, noting the most recent non-purged transaction, or 0 if everything has been purged. On transaction start, we initialize this to 1 more than the transaction start ID. On recovery, the field may be adjusted to the transaction end ID (TRX_UNDO_TRX_NO) if it is larger. The field TRX_UNDO_NEEDS_PURGE becomes write-only; only some debug assertions that would validate the value. The field reflects the old inaccurate Boolean field trx_rseg_t::needs_purge. trx_undo_mem_create_at_db_start(), trx_undo_lists_init(), trx_rseg_mem_restore(): Remove the parameter max_trx_id. Instead, store the maximum in trx_rseg_t::needs_purge, where trx_rseg_array_init() will find it. trx_purge_free_segment(): Contiguously hold a lock on trx_rseg_t to prevent any concurrent allocation of undo log. trx_purge_truncate_rseg_history(): Only invoke trx_purge_free_segment() if the rollback segment is empty and there are no pending transactions associated with it. trx_purge_truncate_history(): Only proceed with innodb_undo_log_truncate=ON if trx_rseg_t::needs_purge indicates that all history has been purged. Tested by: Matthias Leich
2023-02-24 14:24:44 +02:00
--source include/wait_all_purged.inc
--connect (prevent_purge,localhost,root)
START TRANSACTION WITH CONSISTENT SNAPSHOT;
--connection default
2017-08-15 17:18:55 +03:00
INSERT INTO t1 VALUES(1,2),(3,4);
ALTER TABLE t1 ADD COLUMN c INT;
2017-08-15 17:18:55 +03:00
UPDATE t1 SET b=-3 WHERE a=3;
--connect (con1,localhost,root)
BEGIN;
# For purgeable records, we must record DB_TRX_ID=0 in the undo log!
UPDATE t1 SET b=4 WHERE a=3;
--disconnect prevent_purge
--connection default
# Initiate a full purge, which should reset the DB_TRX_ID except for a=3.
SET GLOBAL innodb_max_purge_lag_wait=1;
# Initiate a ROLLBACK of the update, which should reset the DB_TRX_ID for a=3.
MDEV-30671 InnoDB undo log truncation fails to wait for purge of history It is not safe to invoke trx_purge_free_segment() or execute innodb_undo_log_truncate=ON before all undo log records in the rollback segment has been processed. A prominent failure that would occur due to premature freeing of undo log pages is that trx_undo_get_undo_rec() would crash when trying to copy an undo log record to fetch the previous version of a record. If trx_undo_get_undo_rec() was not invoked in the unlucky time frame, then the symptom would be that some committed transaction history is never removed. This would be detected by CHECK TABLE...EXTENDED that was impleented in commit ab0190101b0587e0e03b2d75a967050b9a85fd1b. Such a garbage collection leak should be possible even when using innodb_undo_log_truncate=OFF, just involving trx_purge_free_segment(). trx_rseg_t::needs_purge: Change the type from Boolean to a transaction identifier, noting the most recent non-purged transaction, or 0 if everything has been purged. On transaction start, we initialize this to 1 more than the transaction start ID. On recovery, the field may be adjusted to the transaction end ID (TRX_UNDO_TRX_NO) if it is larger. The field TRX_UNDO_NEEDS_PURGE becomes write-only; only some debug assertions that would validate the value. The field reflects the old inaccurate Boolean field trx_rseg_t::needs_purge. trx_undo_mem_create_at_db_start(), trx_undo_lists_init(), trx_rseg_mem_restore(): Remove the parameter max_trx_id. Instead, store the maximum in trx_rseg_t::needs_purge, where trx_rseg_array_init() will find it. trx_purge_free_segment(): Contiguously hold a lock on trx_rseg_t to prevent any concurrent allocation of undo log. trx_purge_truncate_rseg_history(): Only invoke trx_purge_free_segment() if the rollback segment is empty and there are no pending transactions associated with it. trx_purge_truncate_history(): Only proceed with innodb_undo_log_truncate=ON if trx_rseg_t::needs_purge indicates that all history has been purged. Tested by: Matthias Leich
2023-02-24 14:24:44 +02:00
--connection con1
ROLLBACK;
--disconnect con1
MDEV-30671 InnoDB undo log truncation fails to wait for purge of history It is not safe to invoke trx_purge_free_segment() or execute innodb_undo_log_truncate=ON before all undo log records in the rollback segment has been processed. A prominent failure that would occur due to premature freeing of undo log pages is that trx_undo_get_undo_rec() would crash when trying to copy an undo log record to fetch the previous version of a record. If trx_undo_get_undo_rec() was not invoked in the unlucky time frame, then the symptom would be that some committed transaction history is never removed. This would be detected by CHECK TABLE...EXTENDED that was impleented in commit ab0190101b0587e0e03b2d75a967050b9a85fd1b. Such a garbage collection leak should be possible even when using innodb_undo_log_truncate=OFF, just involving trx_purge_free_segment(). trx_rseg_t::needs_purge: Change the type from Boolean to a transaction identifier, noting the most recent non-purged transaction, or 0 if everything has been purged. On transaction start, we initialize this to 1 more than the transaction start ID. On recovery, the field may be adjusted to the transaction end ID (TRX_UNDO_TRX_NO) if it is larger. The field TRX_UNDO_NEEDS_PURGE becomes write-only; only some debug assertions that would validate the value. The field reflects the old inaccurate Boolean field trx_rseg_t::needs_purge. trx_undo_mem_create_at_db_start(), trx_undo_lists_init(), trx_rseg_mem_restore(): Remove the parameter max_trx_id. Instead, store the maximum in trx_rseg_t::needs_purge, where trx_rseg_array_init() will find it. trx_purge_free_segment(): Contiguously hold a lock on trx_rseg_t to prevent any concurrent allocation of undo log. trx_purge_truncate_rseg_history(): Only invoke trx_purge_free_segment() if the rollback segment is empty and there are no pending transactions associated with it. trx_purge_truncate_history(): Only proceed with innodb_undo_log_truncate=ON if trx_rseg_t::needs_purge indicates that all history has been purged. Tested by: Matthias Leich
2023-02-24 14:24:44 +02:00
--connection default
# Reset the DB_TRX_ID for the hidden ADD COLUMN metadata record.
--source include/wait_all_purged.inc
FLUSH TABLE t1 FOR EXPORT;
2017-08-15 17:18:55 +03:00
# The following is based on innodb.table_flags:
--perl
use strict;
my $ps= $ENV{INNODB_PAGE_SIZE};
my $file= "$ENV{MYSQLD_DATADIR}/test/t1.ibd";
open(FILE, "<", $file) || die "Unable to open $file\n";
my $page;
print "Clustered index root page contents:\n";
sysseek(FILE, 3*$ps, 0) || die "Unable to seek $file";
die "Unable to read $file" unless sysread(FILE, $page, $ps) == $ps;
print "N_RECS=", unpack("n", substr($page,38+16,2));
print "; LEVEL=", unpack("n", substr($page,38+26,2)), "\n";
my @fields=qw(a DB_TRX_ID DB_ROLL_PTR b c);
2017-08-15 17:18:55 +03:00
for (my $offset= 0x65; $offset;
$offset= unpack("n", substr($page,$offset-2,2)))
{
print "header=0x", unpack("H*",substr($page,$offset-6,6)), " (";
my $n_fields= unpack("n", substr($page,$offset-4,2)) >> 1 & 0x3ff;
my $start= 0;
my $name;
for (my $i= 0; $i < $n_fields; $i++) {
my $end= unpack("C", substr($page, $offset-7-$i, 1));
print ",\n " if $i;
print "$fields[$i]=";
if ($end & 0x80) {
print "NULL(", ($end & 0x7f) - $start, " bytes)"
} else {
print "0x", unpack("H*", substr($page,$offset+$start,$end-$start))
}
$start= $end & 0x7f;
}
print ")\n";
}
close(FILE) || die "Unable to close $file\n";
EOF
UNLOCK TABLES;
2017-08-15 17:18:55 +03:00
SELECT * FROM t1;
DROP TABLE t1;
SET GLOBAL innodb_stats_persistent = @save_stats_persistent;