mirror of
https://github.com/MariaDB/server.git
synced 2026-05-15 11:27:39 +02:00
Merge 10.11 into 11.4
This commit is contained in:
commit
7e76a58e0b
10 changed files with 33 additions and 244 deletions
|
|
@ -1,51 +0,0 @@
|
|||
SET @save_stats_persistent = @@GLOBAL.innodb_stats_persistent;
|
||||
SET GLOBAL innodb_stats_persistent = 0;
|
||||
#
|
||||
# MDEV-12288 Reset DB_TRX_ID when the history is removed,
|
||||
# to speed up MVCC
|
||||
#
|
||||
CREATE TABLE t1(a INT PRIMARY KEY, b INT NOT NULL)
|
||||
ROW_FORMAT=REDUNDANT ENGINE=InnoDB;
|
||||
InnoDB 0 transactions not purged
|
||||
connect prevent_purge,localhost,root;
|
||||
START TRANSACTION WITH CONSISTENT SNAPSHOT;
|
||||
connection default;
|
||||
INSERT INTO t1 VALUES(1,2),(3,4);
|
||||
ALTER TABLE t1 ADD COLUMN c INT;
|
||||
UPDATE t1 SET b=-3 WHERE a=3;
|
||||
connect con1,localhost,root;
|
||||
BEGIN;
|
||||
UPDATE t1 SET b=4 WHERE a=3;
|
||||
disconnect prevent_purge;
|
||||
connection default;
|
||||
SET GLOBAL innodb_max_purge_lag_wait=1;
|
||||
connection con1;
|
||||
ROLLBACK;
|
||||
disconnect con1;
|
||||
connection default;
|
||||
InnoDB 0 transactions not purged
|
||||
FLUSH TABLE t1 FOR EXPORT;
|
||||
Clustered index root page contents:
|
||||
N_RECS=3; LEVEL=0
|
||||
header=0x0100000300c6 (a=0x696e66696d756d00)
|
||||
header=0x1000200b0087 (a=0x80000000,
|
||||
DB_TRX_ID=0x000000000000,
|
||||
DB_ROLL_PTR=0x80000000000000,
|
||||
b=0x80000000,
|
||||
c=NULL(4 bytes))
|
||||
header=0x0000100900a6 (a=0x80000001,
|
||||
DB_TRX_ID=0x000000000000,
|
||||
DB_ROLL_PTR=0x80000000000000,
|
||||
b=0x80000002)
|
||||
header=0x000018090074 (a=0x80000003,
|
||||
DB_TRX_ID=0x000000000000,
|
||||
DB_ROLL_PTR=0x80000000000000,
|
||||
b=0x7ffffffd)
|
||||
header=0x040008030000 (a=0x73757072656d756d00)
|
||||
UNLOCK TABLES;
|
||||
SELECT * FROM t1;
|
||||
a b c
|
||||
1 2 NULL
|
||||
3 -3 NULL
|
||||
DROP TABLE t1;
|
||||
SET GLOBAL innodb_stats_persistent = @save_stats_persistent;
|
||||
|
|
@ -12,8 +12,8 @@ SYS_TABLES clustered index root page (8):
|
|||
N_RECS=8; LEVEL=0; INDEX_ID=0x0000000000000001
|
||||
header=0x01000003008d (NAME=0x696e66696d756d00)
|
||||
header=0x0000101500d5 (NAME='SYS_FOREIGN',
|
||||
DB_TRX_ID=0x000000000000,
|
||||
DB_ROLL_PTR=0x80000000000000,
|
||||
DB_TRX_ID=0xXXXXXXXXXXXX,
|
||||
DB_ROLL_PTR=0xXXXXXXXXXXXXXX,
|
||||
ID=0x000000000000000b,
|
||||
N_COLS=0x00000004,
|
||||
TYPE=0x00000001,
|
||||
|
|
@ -22,8 +22,8 @@ header=0x0000101500d5 (NAME='SYS_FOREIGN',
|
|||
CLUSTER_NAME=NULL(0 bytes),
|
||||
SPACE=0x00000000)
|
||||
header=0x000018150122 (NAME='SYS_FOREIGN_COLS',
|
||||
DB_TRX_ID=0x000000000000,
|
||||
DB_ROLL_PTR=0x80000000000000,
|
||||
DB_TRX_ID=0xXXXXXXXXXXXX,
|
||||
DB_ROLL_PTR=0xXXXXXXXXXXXXXX,
|
||||
ID=0x000000000000000c,
|
||||
N_COLS=0x00000004,
|
||||
TYPE=0x00000001,
|
||||
|
|
@ -32,8 +32,8 @@ header=0x000018150122 (NAME='SYS_FOREIGN_COLS',
|
|||
CLUSTER_NAME=NULL(0 bytes),
|
||||
SPACE=0x00000000)
|
||||
header=0x0000201501ae (NAME='SYS_VIRTUAL',
|
||||
DB_TRX_ID=0x000000000000,
|
||||
DB_ROLL_PTR=0x80000000000000,
|
||||
DB_TRX_ID=0xXXXXXXXXXXXX,
|
||||
DB_ROLL_PTR=0xXXXXXXXXXXXXXX,
|
||||
ID=0x000000000000000d,
|
||||
N_COLS=0x00000003,
|
||||
TYPE=0x00000001,
|
||||
|
|
@ -42,8 +42,8 @@ header=0x0000201501ae (NAME='SYS_VIRTUAL',
|
|||
CLUSTER_NAME=NULL(0 bytes),
|
||||
SPACE=0x00000000)
|
||||
header=0x0400301501f2 (NAME='test/tc',
|
||||
DB_TRX_ID=0x000000000000,
|
||||
DB_ROLL_PTR=0x80000000000000,
|
||||
DB_TRX_ID=0xXXXXXXXXXXXX,
|
||||
DB_ROLL_PTR=0xXXXXXXXXXXXXXX,
|
||||
ID=0x000000000000000f,
|
||||
N_COLS=0x80000001,
|
||||
TYPE=0x00000001,
|
||||
|
|
@ -52,8 +52,8 @@ header=0x0400301501f2 (NAME='test/tc',
|
|||
CLUSTER_NAME=NULL(0 bytes),
|
||||
SPACE=0x00000002)
|
||||
header=0x00003815027a (NAME='test/td',
|
||||
DB_TRX_ID=0x000000000000,
|
||||
DB_ROLL_PTR=0x80000000000000,
|
||||
DB_TRX_ID=0xXXXXXXXXXXXX,
|
||||
DB_ROLL_PTR=0xXXXXXXXXXXXXXX,
|
||||
ID=0x0000000000000010,
|
||||
N_COLS=0x80000001,
|
||||
TYPE=0x00000021,
|
||||
|
|
@ -62,8 +62,8 @@ header=0x00003815027a (NAME='test/td',
|
|||
CLUSTER_NAME=NULL(0 bytes),
|
||||
SPACE=0x00000003)
|
||||
header=0x00004815016a (NAME='test/tp',
|
||||
DB_TRX_ID=0x000000000000,
|
||||
DB_ROLL_PTR=0x80000000000000,
|
||||
DB_TRX_ID=0xXXXXXXXXXXXX,
|
||||
DB_ROLL_PTR=0xXXXXXXXXXXXXXX,
|
||||
ID=0x0000000000000012,
|
||||
N_COLS=0x80000001,
|
||||
TYPE=0x000009a1,
|
||||
|
|
@ -72,8 +72,8 @@ header=0x00004815016a (NAME='test/tp',
|
|||
CLUSTER_NAME=NULL(0 bytes),
|
||||
SPACE=0x00000005)
|
||||
header=0x000028150236 (NAME='test/tr',
|
||||
DB_TRX_ID=0x000000000000,
|
||||
DB_ROLL_PTR=0x80000000000000,
|
||||
DB_TRX_ID=0xXXXXXXXXXXXX,
|
||||
DB_ROLL_PTR=0xXXXXXXXXXXXXXX,
|
||||
ID=0x000000000000000e,
|
||||
N_COLS=0x00000001,
|
||||
TYPE=0x00000001,
|
||||
|
|
@ -82,8 +82,8 @@ header=0x000028150236 (NAME='test/tr',
|
|||
CLUSTER_NAME=NULL(0 bytes),
|
||||
SPACE=0x00000001)
|
||||
header=0x000040150074 (NAME='test/tz',
|
||||
DB_TRX_ID=0x000000000000,
|
||||
DB_ROLL_PTR=0x80000000000000,
|
||||
DB_TRX_ID=0xXXXXXXXXXXXX,
|
||||
DB_ROLL_PTR=0xXXXXXXXXXXXXXX,
|
||||
ID=0x0000000000000011,
|
||||
N_COLS=0x80000001,
|
||||
TYPE=0x00000023,
|
||||
|
|
@ -155,6 +155,7 @@ BEGIN;
|
|||
INSERT INTO tr VALUES(1);
|
||||
INSERT INTO tc VALUES(1);
|
||||
INSERT INTO td VALUES(1);
|
||||
INSERT INTO tz VALUES(1);
|
||||
INSERT INTO tp VALUES(1);
|
||||
ROLLBACK;
|
||||
SELECT * FROM tr;
|
||||
|
|
|
|||
|
|
@ -1,83 +0,0 @@
|
|||
--source include/innodb_page_size.inc
|
||||
|
||||
SET @save_stats_persistent = @@GLOBAL.innodb_stats_persistent;
|
||||
SET GLOBAL innodb_stats_persistent = 0;
|
||||
|
||||
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;
|
||||
--source include/wait_all_purged.inc
|
||||
|
||||
--connect (prevent_purge,localhost,root)
|
||||
START TRANSACTION WITH CONSISTENT SNAPSHOT;
|
||||
|
||||
--connection default
|
||||
INSERT INTO t1 VALUES(1,2),(3,4);
|
||||
ALTER TABLE t1 ADD COLUMN c INT;
|
||||
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.
|
||||
--connection con1
|
||||
ROLLBACK;
|
||||
--disconnect con1
|
||||
--connection default
|
||||
# Reset the DB_TRX_ID for the hidden ADD COLUMN metadata record.
|
||||
--source include/wait_all_purged.inc
|
||||
|
||||
FLUSH TABLE t1 FOR EXPORT;
|
||||
# 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);
|
||||
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;
|
||||
SELECT * FROM t1;
|
||||
DROP TABLE t1;
|
||||
|
||||
SET GLOBAL innodb_stats_persistent = @save_stats_persistent;
|
||||
|
|
@ -89,7 +89,9 @@ for (my $offset= 0x65; $offset;
|
|||
my $end= unpack("C", substr($page, $offset-7-$i, 1));
|
||||
print ",\n " if $i;
|
||||
print "$fields[$i]=";
|
||||
if ($end & 0x80) {
|
||||
if ($i == 1 || $i == 2) {
|
||||
print "0x", "XX" x ($end-$start);
|
||||
} elsif ($end & 0x80) {
|
||||
print "NULL(", ($end & 0x7f) - $start, " bytes)"
|
||||
} elsif ($n_fields > 1 && $i == 0) {
|
||||
$name= substr($page,$offset+$start,$end-$start);
|
||||
|
|
@ -210,10 +212,7 @@ BEGIN;
|
|||
INSERT INTO tr VALUES(1);
|
||||
INSERT INTO tc VALUES(1);
|
||||
INSERT INTO td VALUES(1);
|
||||
# We cannot access tz, because due to our fiddling of the NO_ROLLBACK flag,
|
||||
# it now has a record with DB_TRX_ID=0, which is invalid for
|
||||
# transactional tables until MDEV-12288 is implemented.
|
||||
# INSERT INTO tz VALUES(1);
|
||||
INSERT INTO tz VALUES(1);
|
||||
INSERT INTO tp VALUES(1);
|
||||
ROLLBACK;
|
||||
|
||||
|
|
|
|||
|
|
@ -638,7 +638,8 @@ public:
|
|||
{
|
||||
/** The largest encountered transaction identifier for which no
|
||||
transaction was observed to be active. This is a cache to speed up
|
||||
trx_sys_t::find_same_or_older().
|
||||
trx_sys_t::find_same_or_older() as well as to elide some calls to
|
||||
trx_sys_t::find().
|
||||
|
||||
This will be zero-initialized in Pool::Pool() and not initialized
|
||||
when a transaction object in the pool is freed and reused. The
|
||||
|
|
|
|||
|
|
@ -5629,8 +5629,10 @@ func_exit:
|
|||
? lock_clust_rec_some_has_impl(rec, index, offsets)
|
||||
: 0;
|
||||
|
||||
if (trx_t *impl_trx = impl_trx_id
|
||||
? trx_sys.find(current_trx(), impl_trx_id, false)
|
||||
trx_t *trx= current_trx();
|
||||
|
||||
if (trx_t *impl_trx = impl_trx_id > (trx ? trx->max_inactive_id : 0)
|
||||
? trx_sys.find(trx, impl_trx_id, false)
|
||||
: 0) {
|
||||
/* impl_trx could have been committed before we
|
||||
acquire its mutex, but not thereafter. */
|
||||
|
|
@ -6215,7 +6217,7 @@ lock_rec_convert_impl_to_expl(
|
|||
|
||||
trx_id = lock_clust_rec_some_has_impl(rec, index, offsets);
|
||||
|
||||
if (trx_id == 0) {
|
||||
if (trx_id <= caller_trx->max_inactive_id) {
|
||||
return nullptr;
|
||||
}
|
||||
if (UNIV_UNLIKELY(trx_id == caller_trx->id)) {
|
||||
|
|
|
|||
|
|
@ -2413,8 +2413,7 @@ end_of_index:
|
|||
} else if (rec_trx_id < trx->id) {
|
||||
/* Reset the DB_TRX_ID,DB_ROLL_PTR of old rows
|
||||
for which history is not going to be
|
||||
available after the rebuild operation.
|
||||
This essentially mimics row_purge_reset_trx_id(). */
|
||||
available after the rebuild operation. */
|
||||
row->fields[new_trx_id_col].data
|
||||
= const_cast<byte*>(reset_trx_id);
|
||||
row->fields[new_trx_id_col + 1].data
|
||||
|
|
|
|||
|
|
@ -1032,78 +1032,6 @@ bool row_purge_del_mark(purge_node_t *node)
|
|||
return result;
|
||||
}
|
||||
|
||||
/** Reset DB_TRX_ID, DB_ROLL_PTR of a clustered index record
|
||||
whose old history can no longer be observed.
|
||||
@param[in,out] node purge node
|
||||
@param[in,out] mtr mini-transaction (will be started and committed) */
|
||||
static void row_purge_reset_trx_id(purge_node_t* node, mtr_t* mtr)
|
||||
{
|
||||
/* Reset DB_TRX_ID, DB_ROLL_PTR for old records. */
|
||||
mtr->start();
|
||||
|
||||
if (row_purge_reposition_pcur(BTR_MODIFY_LEAF, node, mtr)) {
|
||||
dict_index_t* index = dict_table_get_first_index(
|
||||
node->table);
|
||||
ulint trx_id_pos = index->n_uniq ? index->n_uniq : 1;
|
||||
rec_t* rec = btr_pcur_get_rec(&node->pcur);
|
||||
mem_heap_t* heap = NULL;
|
||||
/* Reserve enough offsets for the PRIMARY KEY and 2 columns
|
||||
so that we can access DB_TRX_ID, DB_ROLL_PTR. */
|
||||
rec_offs offsets_[REC_OFFS_HEADER_SIZE + MAX_REF_PARTS + 3];
|
||||
rec_offs_init(offsets_);
|
||||
rec_offs* offsets = rec_get_offsets(
|
||||
rec, index, offsets_, index->n_core_fields,
|
||||
trx_id_pos + 2, &heap);
|
||||
ut_ad(heap == NULL);
|
||||
|
||||
ut_ad(dict_index_get_nth_field(index, trx_id_pos)
|
||||
->col->mtype == DATA_SYS);
|
||||
ut_ad(dict_index_get_nth_field(index, trx_id_pos)
|
||||
->col->prtype == (DATA_TRX_ID | DATA_NOT_NULL));
|
||||
ut_ad(dict_index_get_nth_field(index, trx_id_pos + 1)
|
||||
->col->mtype == DATA_SYS);
|
||||
ut_ad(dict_index_get_nth_field(index, trx_id_pos + 1)
|
||||
->col->prtype == (DATA_ROLL_PTR | DATA_NOT_NULL));
|
||||
|
||||
/* Only update the record if DB_ROLL_PTR matches (the
|
||||
record has not been modified after this transaction
|
||||
became purgeable) */
|
||||
if (node->roll_ptr
|
||||
== row_get_rec_roll_ptr(rec, index, offsets)) {
|
||||
ut_ad(!rec_get_deleted_flag(
|
||||
rec, rec_offs_comp(offsets))
|
||||
|| rec_is_alter_metadata(rec, *index));
|
||||
DBUG_LOG("purge", "reset DB_TRX_ID="
|
||||
<< ib::hex(row_get_rec_trx_id(
|
||||
rec, index, offsets)));
|
||||
|
||||
index->set_modified(*mtr);
|
||||
buf_block_t* block = btr_pcur_get_block(&node->pcur);
|
||||
if (UNIV_LIKELY_NULL(block->page.zip.data)) {
|
||||
page_zip_write_trx_id_and_roll_ptr(
|
||||
block, rec, offsets, trx_id_pos,
|
||||
0, 1ULL << ROLL_PTR_INSERT_FLAG_POS,
|
||||
mtr);
|
||||
} else {
|
||||
ulint len;
|
||||
byte* ptr = rec_get_nth_field(
|
||||
rec, offsets, trx_id_pos, &len);
|
||||
ut_ad(len == DATA_TRX_ID_LEN);
|
||||
size_t offs = ptr - block->page.frame;
|
||||
mtr->memset(block, offs, DATA_TRX_ID_LEN, 0);
|
||||
offs += DATA_TRX_ID_LEN;
|
||||
mtr->write<1,mtr_t::MAYBE_NOP>(
|
||||
*block, block->page.frame + offs,
|
||||
0x80U);
|
||||
mtr->memset(block, offs + 1,
|
||||
DATA_ROLL_PTR_LEN - 1, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mtr->commit();
|
||||
}
|
||||
|
||||
/***********************************************************//**
|
||||
Purges an update of an existing record. Also purges an update of a delete
|
||||
marked record if that record contained an externally stored field. */
|
||||
|
|
@ -1233,8 +1161,6 @@ skip_secondaries:
|
|||
mtr.commit();
|
||||
}
|
||||
}
|
||||
|
||||
row_purge_reset_trx_id(node, &mtr);
|
||||
}
|
||||
|
||||
#ifdef UNIV_DEBUG
|
||||
|
|
@ -1530,8 +1456,6 @@ row_purge_record_func(
|
|||
/* fall through */
|
||||
default:
|
||||
if (!updated_extern) {
|
||||
mtr_t mtr;
|
||||
row_purge_reset_trx_id(node, &mtr);
|
||||
break;
|
||||
}
|
||||
/* fall through */
|
||||
|
|
|
|||
|
|
@ -6384,16 +6384,13 @@ rec_loop:
|
|||
ULINT_UNDEFINED, &heap);
|
||||
goto next_rec;
|
||||
}
|
||||
else if (!rec_deleted && !rec_trx_id);
|
||||
else if (!rec_deleted);
|
||||
else if (!check_table_extended_view.changes_visible(rec_trx_id));
|
||||
else if (prebuilt->autoinc_error == DB_SUCCESS)
|
||||
{
|
||||
const char *msg= rec_deleted
|
||||
? "Unpurged clustered index record"
|
||||
: "Clustered index record with stale history";
|
||||
|
||||
ib::warn w;
|
||||
w << msg << " in table " << index->table->name << ": "
|
||||
w << "Unpurged clustered index record in table "
|
||||
<< index->table->name << ": "
|
||||
<< rec_offsets_print(rec, offsets);
|
||||
prebuilt->autoinc_error= DB_MISSING_HISTORY;
|
||||
push_warning_printf(prebuilt->trx->mysql_thd,
|
||||
|
|
|
|||
|
|
@ -123,7 +123,7 @@ row_vers_impl_x_locked_low(
|
|||
ULINT_UNDEFINED, &heap);
|
||||
|
||||
trx_id = row_get_rec_trx_id(clust_rec, clust_index, clust_offsets);
|
||||
if (trx_id == 0) {
|
||||
if (trx_id <= caller_trx->max_inactive_id) {
|
||||
/* The transaction history was already purged. */
|
||||
mem_heap_free(heap);
|
||||
DBUG_RETURN(0);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue